예제 #1
0
Matrix* setupCanonicalMatrix(int nvtxs, int nedges, idxtype* xadj,
	idxtype* adjncy, idxtype* adjwgt, int ncutify)
{
	int i,j;
	Matrix* ret;

	if ( ncutify )
		ret=allocMatrix(nvtxs,nedges,1,0,0);
	else
		ret=allocMatrix(nvtxs,nedges,0,0,0);
		
	idxcopy(nvtxs+1, xadj, ret->xadj); 
	idxcopy(nedges, adjncy, ret->adjncy);
	if ( adjwgt != NULL )
	{
		if ( ncutify )
		{
			for(i=0;i<ret->nvtxs;i++)
			{
				ret->adjwgtsum[i]=0;
				for(j=ret->xadj[i];j<ret->xadj[i+1];j++)
				{

					ret->adjwgt[j]=(wgttype)adjwgt[j];
				
					ret->adjwgtsum[i]+=ret->adjwgt[j];
				}
			}
			//ncutifyWeights(ret,1,ncutify);  //YK removed
		}
		else
		{
			for(i=0;i<nedges;i++)
				ret->adjwgt[i]=(wgttype)adjwgt[i];
		}
		

		normalizeColumns(ret,1,0);
	}
	else
	{
		if ( ncutify )
			ncutifyWeights(ret,0,ncutify);
		normalizeColumns(ret,0,0);
	}

	// sort each column in ascending order. This is necessary for
	// getDprAdjMatrix. 
	for(i=0;i<nvtxs;i++)
	{
		ParallelQSort(ret->adjncy,ret->adjwgt,ret->xadj[i],ret->xadj[i+1]-1);
	}
	return ret;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{

    double * R_KTg, * chainsPrior_Kg, * A_KKg, * xi_pseudocounts_KK;
    
    int K, T, B;
    int j, k, t;

    double * hM_KTg, * xi_KKBg, * updated_chainsPrior_Kg, * updated_A_KKg, * divergenceContributions;
    
    /* I will need the logs of chainsPrior_Kg, A_KKg, but the log of A_KKg 
       is the only one for which I'd say computations by memorizing the results.
     */
    double * log_chainsPrior_Kg, * log_A_KKg;
    double * rownormalized_xi_KKBg;
    
    
    double * outputToolPtr;
    int trplarr_ndim = 3;
    int * trplarr_dims = mxMalloc(trplarr_ndim*sizeof(int));
    
    double logeps;
    
    if ( !(3<=nrhs && nrhs<=4) || !(1<=nlhs && nlhs<=5))
        mexErrMsgTxt("hmmmix_frugal_hM_KTg_MatlabC requires 3-4 inputs and 1-5 outputs");

    R_KTg = mxGetPr(prhs[0]);
    chainsPrior_Kg = mxGetPr(prhs[1]);
    A_KKg = mxGetPr(prhs[2]);

    
    K = mxGetM(prhs[0]);
    T = mxGetN(prhs[0]);
    
    /* I decided to define B=T-1 because a needed a single letter name for
     * that quantity T-1. I thought naming xi_KKTg when it actually had T-1
     * elements in the last dimension was more confusing than naming it
     * xi_KKBg. I'm not sure if this is a good call.
     */
    B = T-1;
    assert(mxGetM(prhs[1])*mxGetN(prhs[1]) == K);
    assert(mxGetM(prhs[2]) == K);
    assert(mxGetN(prhs[2]) == K);
    
    /* We're going to be using this value to make sure that the zeros in
     * the transition matrices correspond logs whose values are very small
     * compared the the loglikelihoods that we're dealing with in R_KTg.
     */
    logeps = T*vectorMinimum(R_KTg, K*T);
    if (logeps > 0)
        logeps = -T;
    
    /* Our implementation of fwd_back works with logs so we need to make
     * the conversions somewhere. It's a bit stupid to do it in C instead
     * of doing in Matlab with a wrapper, though.
     */
    
    log_A_KKg = mxMalloc(K*K*sizeof(double));
    for (k=0;k<K*K;++k) {
        if (A_KKg[k] < 0) {
            mexPrintf("Found a value < 0 in a transition matrix.\n");
            for (k=0;k<K*K;++k)
                mexPrintf("A_KKg[%d]=%f.\n", k, A_KKg[k]);
            mexErrMsgTxt("transition matrix fault");
        } else if (A_KKg[k] == 0)
            log_A_KKg[k] = logeps;
        else
            log_A_KKg[k] = log(A_KKg[k]);
    }

    log_chainsPrior_Kg = mxMalloc(K*sizeof(double));
    for (k=0;k<K;++k) {
        if (chainsPrior_Kg[k] < 0) {
            mexPrintf("Found a value < 0 in a the initial state priors.\n");
            for (k=0;k<K*K;++k)
                mexPrintf("chainsPrior_Kg[%d]=%f.\n", k, chainsPrior_Kg[k]);
            mexErrMsgTxt("initial state prior fault");
        } else if (chainsPrior_Kg[k] == 0)
            log_chainsPrior_Kg[k] = logeps;
        else
            log_chainsPrior_Kg[k] = log(chainsPrior_Kg[k]);
    }
    
    /* If no pseudocounts were supplied, we fill up the values with zeros. */
    if (4<=nrhs)
        xi_pseudocounts_KK = mxGetPr(prhs[3]);
    else {
        xi_pseudocounts_KK = mxMalloc(K*K*sizeof(double));
        for (k=0; k<K*K; ++k)
            xi_pseudocounts_KK[k] = 0;
    }
    

    /*  assign the memory for the variables in which we'll construct
        the arrays of values that we want to output
     */
    hM_KTg = mxMalloc(K*T*sizeof(double));
    xi_KKBg = mxMalloc(K*K*B*sizeof(double));
    updated_chainsPrior_Kg = mxMalloc(K*sizeof(double));
    updated_A_KKg = mxMalloc(K*K*sizeof(double));

    /* DEBUGGING
    for(k=0;k<K;++k)
        mexPrintf("log_chainsPrior_Kg[%d]=%f\n", k,log_chainsPrior_Kg[k]);
    for(k=0;k<K*K;++k)
        mexPrintf("log_A_KKg[%d]=%f\n", k,log_A_KKg[k]);
    */

    /* Drowned in all the code, this is the line that makes the call to the
     * fwd_back code that does the work.
     */
    
    fwd_back(hM_KTg, xi_KKBg, log_chainsPrior_Kg, log_A_KKg, 0, R_KTg, K, T, 1);
    /* The C function spits out values in log form so we have to exponentiate
     * and then normalize them. We could have used intermediary variables, but
     * this is C so we're being greedy with memory.
     */
    
    for(k=0;k<K*T;++k)
        hM_KTg[k] = exp(hM_KTg[k]);
    normalizeColumns(hM_KTg, K, T, 0);
    for(k=0;k<K*K*B;++k)
        xi_KKBg[k] = exp(xi_KKBg[k]);
    normalizeColumns(xi_KKBg, K*K, B, 0);
    
    
    
    /* find the MLE for A_KKg using the twoslice marginals in xi_KKBg */
    if (nlhs >= 2) {
        /* the T-1 is because the last values are junk */
        transition_matrix_MLE_from_twoslice_marginals_pseudocounts_normalized(updated_A_KKg, xi_KKBg, K, T-1, xi_pseudocounts_KK);
    }

    /* It's a bit pointless to have another variable for that, but I'm not
     *  completely sure right now if the "pi" vector for HMM corresponds to
     *  the first filtered states or it's not that at all.
     */
    for (k=0;k<K;++k)
        updated_chainsPrior_Kg[k] = hM_KTg[k];
    
    /* Now comes the divergence contributions, the complicated part.
     * I'll return 3 values. The first term without the "S" factor in front,
     * the hM log(hM) entropy and then the result of
     *      S*(first term) - (second term)
     */
    if (nlhs >= 5) {
        
        /* initialization */
        
        divergenceContributions = mxMalloc(2*sizeof(double));
        
        rownormalized_xi_KKBg = mxMalloc(K*K*B*sizeof(double));
        memcpy(rownormalized_xi_KKBg, xi_KKBg, K*K*B*sizeof(double));
        for (t=0; t<T-1; ++t)
            normalizeRows(rownormalized_xi_KKBg + K*K*t, K, K, 1e-16);
        
        divergenceContributions[0] = 0;
        divergenceContributions[1] = 0;

        
        /* on R_KTg */
        for (t=0;t<T;++t) {
            for (k=0; k<K; ++k) {
                divergenceContributions[0] += hM_KTg[k+K*t] * R_KTg[k+K*t];
            }
        }
        
        /* log f(M|A,pi) */
        for (k=0;k<K;++k) {
            divergenceContributions[0] += hM_KTg[k + K*0] * log_chainsPrior_Kg[k];
            divergenceContributions[1] += hM_KTg[k + K*0] * log(hM_KTg[k + K*0] + 1e-16);
        }
            
        for (t=0;t<T-1;++t) {
            for (k=0; k<K; ++k) {
                for (j=0; j<K; ++j) {
                    /* newer, maybe right ? */
                    divergenceContributions[0] += hM_KTg[k + K*t] * rownormalized_xi_KKBg[k+K*j+K*K*t] * log_A_KKg[k+K*j];
                    divergenceContributions[1] += hM_KTg[k + K*t] * rownormalized_xi_KKBg[k+K*j+K*K*t] * log(rownormalized_xi_KKBg[k+K*j+K*K*t] + 1e-16);
                    
                    /* older, probably wrong
                    divergenceContributions[0] += xi_KKTg[k+K*j+K*K*t] * log_A_KKg[k+K*j];
                    divergenceContributions[1] += xi_KKTg[k+K*j+K*K*t] * log(rownormalized_xi_KKTg[k+K*j+K*K*t] + 1e-16);
                     */
                }
            }
        }

        /* the pseudocounts. Don't forget to call the function 
         * hmmmix_pseudoCounts_logNormalizingConstant(A,pseudoCounts)
         * in Matlab after to get the correct divergence term.
         */
        for (k=0; k<K; ++k) {
            for (j=0; j<K; ++j) {
                divergenceContributions[0] += xi_pseudocounts_KK[k+K*j] * log_A_KKg[k+K*j];
            }
        }
        
    }
    
    
    /* output to Matlab */
    
    if (nlhs >= 1) {
        plhs[0] = mxCreateDoubleMatrix(K,T,mxREAL);
        outputToolPtr = mxGetPr(plhs[0]);
        memcpy(outputToolPtr, hM_KTg, K*T*sizeof(double));
    }

    if (nlhs >= 2) {
        trplarr_dims[0] = K;
        trplarr_dims[1] = K;
        trplarr_dims[2] = T-1;
        
        plhs[1] = mxCreateNumericArray(trplarr_ndim, trplarr_dims, mxDOUBLE_CLASS, mxREAL);
        outputToolPtr = mxGetPr(plhs[1]);
        memcpy(outputToolPtr, xi_KKBg, K*K*B*sizeof(double));
    }

    if (nlhs >= 3) {
        plhs[2] = mxCreateDoubleMatrix(K,1,mxREAL);
        outputToolPtr = mxGetPr(plhs[2]);
        memcpy(outputToolPtr, updated_chainsPrior_Kg, K*sizeof(double));
    }

    if (nlhs >= 4) {
        plhs[3] = mxCreateDoubleMatrix(K,K,mxREAL);
        outputToolPtr = mxGetPr(plhs[3]);
        memcpy(outputToolPtr, updated_A_KKg, K*K*sizeof(double));
    }
    
    if (nlhs >= 5) {
        plhs[4] = mxCreateDoubleMatrix(2,1,mxREAL);
        outputToolPtr = mxGetPr(plhs[4]);
        memcpy(outputToolPtr, divergenceContributions, 2*sizeof(double));
    }
    
    /* cleaning up */
    
    mxFree(trplarr_dims);
    mxFree(hM_KTg);  mxFree(xi_KKBg);
    mxFree(updated_A_KKg);  mxFree(updated_chainsPrior_Kg);
    mxFree(log_A_KKg); mxFree(log_chainsPrior_Kg);
    
    /* because we allocate xi_pseudocounts_KK when (4<=nrhs) fails */
    if (4>nrhs)
        mxFree(xi_pseudocounts_KK);

        
    if (nlhs >= 5) {
        mxFree(divergenceContributions);
        mxFree(rownormalized_xi_KKBg);
    }
    
        
    return;
}