/* Function: esl_vec_DLogValidate() * Synopsis: Verify that vector is a log-p-vector. * Incept: ER, Tue Dec 5 09:46:51 EST 2006 [janelia] * * Purpose: Validate a log probability vector <vec> of length <n>. * The exp of each element has to be between 0 and 1, and * the sum of all elements has to be 1. * * Args: v - log p vector to validate. * n - dimensionality of v * tol - convergence criterion applied to sum of exp v * errbuf - NULL, or a failure message buffer allocated * for at least p7_ERRBUFSIZE chars. * * Returns: <eslOK> on success, or <eslFAIL> on failure; upon failure, * if caller provided a non-<NULL> <errbuf>, an informative * message is left there. * * Throws: <eslEMEM> on allocation failure. */ int esl_vec_DLogValidate(double *vec, int n, double tol, char *errbuf) { int status; double *expvec = NULL; if (errbuf) *errbuf = 0; if (n == 0) return eslOK; ESL_ALLOC(expvec, sizeof(double)*n); esl_vec_DCopy(vec, n, expvec); esl_vec_DExp(expvec, n); if ((status = esl_vec_DValidate(expvec, n, tol, errbuf)) != eslOK) goto ERROR; free(expvec); return eslOK; ERROR: if (expvec != NULL) free(expvec); return status; }
static void utest_pvectors(void) { char *msg = "pvector unit test failed"; double p1[4] = { 0.25, 0.25, 0.25, 0.25 }; double p2[4]; double p3[4]; float p1f[4]; float p2f[4] = { 0.0, 0.5, 0.5, 0.0 }; float p3f[4]; int n = 4; double result; esl_vec_D2F(p1, n, p1f); esl_vec_F2D(p2f, n, p2); if (esl_vec_DValidate(p1, n, 1e-12, NULL) != eslOK) esl_fatal(msg); if (esl_vec_FValidate(p1f, n, 1e-7, NULL) != eslOK) esl_fatal(msg); result = esl_vec_DEntropy(p1, n); if (esl_DCompare(2.0, result, 1e-9) != eslOK) esl_fatal(msg); result = esl_vec_FEntropy(p1f, n); if (esl_DCompare(2.0, result, 1e-9) != eslOK) esl_fatal(msg); result = esl_vec_DEntropy(p2, n); if (esl_DCompare(1.0, result, 1e-9) != eslOK) esl_fatal(msg); result = esl_vec_FEntropy(p2f, n); if (esl_DCompare(1.0, result, 1e-9) != eslOK) esl_fatal(msg); result = esl_vec_DRelEntropy(p2, p1, n); if (esl_DCompare(1.0, result, 1e-9) != eslOK) esl_fatal(msg); result = esl_vec_FRelEntropy(p2f, p1f, n); if (esl_DCompare(1.0, result, 1e-9) != eslOK) esl_fatal(msg); result = esl_vec_DRelEntropy(p1, p2, n); if (result != eslINFINITY) esl_fatal(msg); result = esl_vec_FRelEntropy(p1f, p2f, n); if (result != eslINFINITY) esl_fatal(msg); esl_vec_DLog(p2, n); if (esl_vec_DLogValidate(p2, n, 1e-12, NULL) != eslOK) esl_fatal(msg); esl_vec_DExp(p2, n); if (p2[0] != 0.) esl_fatal(msg); esl_vec_FLog(p2f, n); if (esl_vec_FLogValidate(p2f, n, 1e-7, NULL) != eslOK) esl_fatal(msg); esl_vec_FExp(p2f, n); if (p2f[0] != 0.) esl_fatal(msg); esl_vec_DCopy(p2, n, p3); esl_vec_DScale(p3, n, 10.); esl_vec_DNorm(p3, n); if (esl_vec_DCompare(p2, p3, n, 1e-12) != eslOK) esl_fatal(msg); esl_vec_DLog(p3, n); result = esl_vec_DLogSum(p3, n); if (esl_DCompare(0.0, result, 1e-12) != eslOK) esl_fatal(msg); esl_vec_DIncrement(p3, n, 2.0); esl_vec_DLogNorm(p3, n); if (esl_vec_DCompare(p2, p3, n, 1e-12) != eslOK) esl_fatal(msg); esl_vec_FCopy(p2f, n, p3f); esl_vec_FScale(p3f, n, 10.); esl_vec_FNorm(p3f, n); if (esl_vec_FCompare(p2f, p3f, n, 1e-7) != eslOK) esl_fatal(msg); esl_vec_FLog(p3f, n); result = esl_vec_FLogSum(p3f, n); if (esl_DCompare(0.0, result, 1e-7) != eslOK) esl_fatal(msg); esl_vec_FIncrement(p3f, n, 2.0); esl_vec_FLogNorm(p3f, n); if (esl_vec_FCompare(p2f, p3f, n, 1e-7) != eslOK) esl_fatal(msg); return; }
/* Function: p7_profile_Validate() * * Purpose: Validates the internals of the generic profile structure * <gm>. * * Returns: <eslOK> if <gm> internals look fine. Returns <eslFAIL> * if something is wrong, and leaves an error message in * <errbuf> if caller passed it non-<NULL>. */ int p7_profile_Validate(const P7_PROFILE *gm, char *errbuf, float tol) { int k; int M = gm->M; double *pstart = NULL; int status; ESL_ALLOC(pstart, sizeof(double) * (gm->M+1)); /* Validate tsc[0] boundary condition: * tLM, tGM, tDGE are valid transitions at nonexistent node k=0, * because of their off-by-one storage (i.e. tsc[k-1,LM] = tLk->M) */ if (P7P_TSC(gm, 0, p7P_MM) != -eslINFINITY || P7P_TSC(gm, 0, p7P_IM) != -eslINFINITY || P7P_TSC(gm, 0, p7P_DM) != -eslINFINITY || // LM, GM skipped past... P7P_TSC(gm, 0, p7P_MD) != -eslINFINITY || P7P_TSC(gm, 0, p7P_DD) != -eslINFINITY || P7P_TSC(gm, 0, p7P_MI) != -eslINFINITY || P7P_TSC(gm, 0, p7P_II) != -eslINFINITY) ESL_XFAIL(eslFAIL, errbuf, "transition probs at 0 not set properly"); // DGE skipped. /* Validate tsc[M] boundary conditions. * t(Mm->D) = 0 as an initialization condition to make Backward work * t(Dm->D) = 0 ditto * t(DGE,k) = t(Dk+1->..->Dm->E) = 0 at k=M and k=M-1 */ if (P7P_TSC(gm, M, p7P_MM) != -eslINFINITY || P7P_TSC(gm, M, p7P_IM) != -eslINFINITY || P7P_TSC(gm, M, p7P_DM) != -eslINFINITY || P7P_TSC(gm, M, p7P_LM) != -eslINFINITY || P7P_TSC(gm, M, p7P_GM) != -eslINFINITY || /*... MD DD ... */ P7P_TSC(gm, M, p7P_MI) != -eslINFINITY || P7P_TSC(gm, M, p7P_II) != -eslINFINITY) ESL_XFAIL(eslFAIL, errbuf, "transition probs at M not set properly"); if (P7P_TSC(gm, M, p7P_MD) != 0.0f || P7P_TSC(gm, M, p7P_DD) != 0.0f || P7P_TSC(gm, M, p7P_DGE) != 0.0f) ESL_XFAIL(eslFAIL, errbuf, "transition probs at M not set properly"); if (M>1 && P7P_TSC(gm, M-1, p7P_DGE) != 0.0f) ESL_XFAIL(eslFAIL, errbuf, "transition probs at M not set properly"); /* Validate local entry distribution. * this is an implicit probability distribution, * corresponding to the implicit local alignment model, and we have * to calculate the M(M+1)/2 fragment probabilities accordingly. */ pstart[0] = 0.0; for (k = 1; k <= gm->M; k++) { pstart[k] = exp(P7P_TSC(gm, k-1, p7P_LM)) * (gm->M - k + 1); /* multiply p_ij by the number of exits j; note off-by-one storage, L->Mk in tsc[k-1] */ if (pstart[k] > 1.0 && pstart[k] <= 1.0 + tol) pstart[k] = 1.0; // There's a special case, where only one M state is occupiable, with entry prob 1.0/(M-k+1). (M-k+1)*exp(log(1.0/M-k+1)) can give 1+epsilon. } if (esl_vec_DValidate(pstart, gm->M+1, tol, NULL) != eslOK) ESL_XFAIL(eslFAIL, errbuf, "local entry distribution is not normalized properly"); /* Validate the glocal entry distribution. This is an explicit * probability distribution, corresponding to left wing retraction. * To make it sum to one, we also have to add in the probability * of the mute cycle G->D1...Dm->E; we put this in pstart[0]. * [SRE:J9/98]. */ for (k = 1; k <= gm->M; k++) pstart[k] = exp(P7P_TSC(gm, k-1, p7P_GM)); /* mute path probability */ p7_profile_GetMutePathLogProb(gm, &(pstart[0])); pstart[0] = exp(pstart[0]); /* this will often underflow, but when it does, it means that path's negligible in p, and the validation of the sum will still succeed */ if (esl_vec_DValidate(pstart, gm->M+1, tol, NULL) != eslOK) ESL_XFAIL(eslFAIL, errbuf, "glocal entry distribution is not normalized properly"); free(pstart); return eslOK; ERROR: if (pstart != NULL) free(pstart); return eslFAIL; }