/* EMBLEM and SLIPCASE Copyright (c) 2013, Fabrizio Riguzzi and Elena Bellodi This package uses the library cudd, see http://vlsi.colorado.edu/~fabio/CUDD/ for the relative license. */ #include "config.h" #include "cudd_config.h" #include #include #include #include #if HAVE_CUDD_CUDD_H #include #elif HAVE_CUDD_H #include "cudd.h" #endif #include "YapInterface.h" #define LOGZERO log(0.000001) #define CACHE_SLOTS 1 #define UNIQUE_SLOTS 1 typedef struct { int nVal, nRule; int firstBoolVar; } variable; typedef struct { DdNode *key; double value; } rowel; typedef struct { int cnt; rowel *row; } tablerow; tablerow *table; static variable **vars_ex; static int **bVar2mVar_ex; static double *sigma; static double ***eta; static double ***eta_temp; static double **arrayprob; static int *rules; static DdManager **mgr_ex; static int *nVars_ex; static int nRules; double *nodes_probs_ex; double **probs_ex; static int *boolVars_ex; tablerow *nodesB; tablerow *nodesF; int ex, cycle; DdNode ***nodesToVisit; int *NnodesToVisit; double *example_prob; static YAP_Bool ret_prob(void); double Prob(DdNode *node, int comp_par); static YAP_Bool end_bdd(void); static YAP_Bool init_test(void); static YAP_Bool add_var(void); static YAP_Bool init(void); static YAP_Bool end(void); static YAP_Bool EM(void); static YAP_Bool Q(void); double ProbPath(DdNode *node, int comp_par, int nex); static YAP_Bool rec_deref(void); int indexMvar(DdNode *node); void Forward(DdNode *node, int nex); void GetForward(DdNode *node, double ForwProbPath); void UpdateForward(DdNode *node, int nex); double GetOutsideExpe(DdNode *root, double ex_prob, int nex); void Maximization(void); static double Expectation(DdNode **nodes_ex, int lenNodes); void init_my_predicates(void); FILE *open_file(char *filename, const char *mode); tablerow *init_table(int varcnt); double *get_value(tablerow *tab, DdNode *node); void add_or_replace_node(tablerow *tab, DdNode *node, double value); void add_node(tablerow *tab, DdNode *node, double value); void destroy_table(tablerow *tab, int varcnt); static YAP_Bool init(void) { int j, i; YAP_Term arg1, arg2, list; ex = 0; cycle = 0; arg1 = YAP_ARG1; arg2 = YAP_ARG2; nRules = YAP_IntOfTerm(arg1); vars_ex = NULL; nVars_ex = NULL; eta = (double ***)malloc(nRules * sizeof(double **)); eta_temp = (double ***)malloc(nRules * sizeof(double **)); rules = (int *)malloc(nRules * sizeof(int)); arrayprob = (double **)malloc(nRules * sizeof(double *)); probs_ex = NULL; bVar2mVar_ex = NULL; boolVars_ex = NULL; mgr_ex = NULL; nodes_probs_ex = NULL; list = arg2; for (j = 0; j < nRules; j++) { rules[j] = YAP_IntOfTerm(YAP_HeadOfTerm(list)); list = YAP_TailOfTerm(list); eta[j] = (double **)malloc((rules[j] - 1) * sizeof(double *)); eta_temp[j] = (double **)malloc((rules[j] - 1) * sizeof(double *)); arrayprob[j] = (double *)malloc((rules[j] - 1) * sizeof(double)); for (i = 0; i < rules[j] - 1; i++) { eta[j][i] = (double *)malloc(2 * sizeof(double)); eta_temp[j][i] = (double *)malloc(2 * sizeof(double)); } } return 1; } static YAP_Bool init_bdd(void) { mgr_ex = (DdManager **)realloc(mgr_ex, (ex + 1) * sizeof(DdManager *)); mgr_ex[ex] = Cudd_Init(0, 0, UNIQUE_SLOTS, CACHE_SLOTS, 5120); Cudd_AutodynEnable(mgr_ex[ex], CUDD_REORDER_GROUP_SIFT); Cudd_SetMaxCacheHard(mgr_ex[ex], 0); Cudd_SetLooseUpTo(mgr_ex[ex], 0); Cudd_SetMinHit(mgr_ex[ex], 15); bVar2mVar_ex = (int **)realloc(bVar2mVar_ex, (ex + 1) * sizeof(int *)); bVar2mVar_ex[ex] = NULL; vars_ex = (variable **)realloc(vars_ex, (ex + 1) * sizeof(variable *)); vars_ex[ex] = NULL; nVars_ex = (int *)realloc(nVars_ex, (ex + 1) * sizeof(int)); nVars_ex[ex] = 0; probs_ex = (double **)realloc(probs_ex, (ex + 1) * sizeof(double *)); probs_ex[ex] = NULL; boolVars_ex = (int *)realloc(boolVars_ex, (ex + 1) * sizeof(int)); boolVars_ex[ex] = 0; return 1; } static YAP_Bool end_bdd(void) { ex = ex + 1; return 1; } static YAP_Bool init_test(void) { YAP_Term arg1; arg1 = YAP_ARG1; nRules = YAP_IntOfTerm(arg1); ex = 0; mgr_ex = (DdManager **)malloc((ex + 1) * sizeof(DdManager *)); mgr_ex[ex] = Cudd_Init(0, 0, UNIQUE_SLOTS, CACHE_SLOTS, 5120); Cudd_AutodynEnable(mgr_ex[ex], CUDD_REORDER_GROUP_SIFT); Cudd_SetMaxCacheHard(mgr_ex[ex], 0); Cudd_SetLooseUpTo(mgr_ex[ex], 0); Cudd_SetMinHit(mgr_ex[ex], 15); bVar2mVar_ex = (int **)malloc((ex + 1) * sizeof(int *)); bVar2mVar_ex[ex] = NULL; vars_ex = (variable **)malloc((ex + 1) * sizeof(variable *)); vars_ex[ex] = NULL; nVars_ex = (int *)malloc((ex + 1) * sizeof(int)); nVars_ex[ex] = 0; probs_ex = (double **)malloc((ex + 1) * sizeof(double *)); probs_ex[ex] = NULL; boolVars_ex = (int *)malloc((ex + 1) * sizeof(int)); boolVars_ex[ex] = 0; rules = (int *)malloc(nRules * sizeof(int)); return 1; } static YAP_Bool end_test(void) { free(bVar2mVar_ex[ex]); free(vars_ex[ex]); Cudd_Quit(mgr_ex[ex]); free(probs_ex[ex]); free(rules); free(mgr_ex); free(bVar2mVar_ex); free(vars_ex); free(probs_ex); free(nVars_ex); free(boolVars_ex); return 1; } static double Expectation(DdNode **nodes_ex, int lenNodes) { int i; double rootProb, CLL = 0; for (i = 0; i < lenNodes; i++) { if (!Cudd_IsConstant(nodes_ex[i])) { nodesB = init_table(boolVars_ex[i]); nodesF = init_table(boolVars_ex[i]); Forward(nodes_ex[i], i); rootProb = GetOutsideExpe(nodes_ex[i], example_prob[i], i); if (rootProb <= 0.0) CLL = CLL + LOGZERO * example_prob[i]; else CLL = CLL + log(rootProb) * example_prob[i]; nodes_probs_ex[i] = rootProb; destroy_table(nodesB, boolVars_ex[i]); destroy_table(nodesF, boolVars_ex[i]); } else if (nodes_ex[i] == Cudd_ReadLogicZero(mgr_ex[i])) { CLL = CLL + LOGZERO * example_prob[i]; nodes_probs_ex[i] = 0.0; } else nodes_probs_ex[i] = 1.0; } return CLL; } static YAP_Bool end(void) { int r, i; for (i = 0; i < ex; i++) { Cudd_Quit(mgr_ex[i]); free(bVar2mVar_ex[i]); free(vars_ex[i]); free(probs_ex[i]); fflush(stdout); } free(mgr_ex); free(bVar2mVar_ex); free(vars_ex); free(probs_ex); free(nVars_ex); free(boolVars_ex); for (r = 0; r < nRules; r++) { for (i = 0; i < rules[r] - 1; i++) { free(eta[r][i]); free(eta_temp[r][i]); } free(eta[r]); free(eta_temp[r]); } free(eta); free(eta_temp); for (r = 0; r < nRules; r++) { free(arrayprob[r]); } free(arrayprob); free(rules); return 1; } static YAP_Bool ret_prob(void) { YAP_Term arg1, arg2, out; DdNode *node; arg1 = YAP_ARG1; arg2 = YAP_ARG2; node = (DdNode *)YAP_IntOfTerm(arg1); if (!Cudd_IsConstant(node)) { table = init_table(boolVars_ex[ex]); out = YAP_MkFloatTerm(Prob(node, 0)); destroy_table(table, boolVars_ex[ex]); } else { if (node == Cudd_ReadOne(mgr_ex[ex])) out = YAP_MkFloatTerm(1.0); else out = YAP_MkFloatTerm(0.0); } return (YAP_Unify(out, arg2)); } double Prob(DdNode *node, int comp_par) /* compute the probability of the expression rooted at node. table is used to store nodeB for which the probability has alread been computed so that it is not recomputed */ { int index, mVarIndex, comp; variable v; double res; double p, pt, pf, BChild0, BChild1; double *value_p; DdNode *nodekey, *T, *F; comp = Cudd_IsComplement(node); comp = (comp && !comp_par) || (!comp && comp_par); if (Cudd_IsConstant(node)) { if (comp) return 0.0; else return 1.0; } else { nodekey = Cudd_Regular(node); value_p = get_value(table, nodekey); if (value_p != NULL) return *value_p; else { index = Cudd_NodeReadIndex(node); // Returns the index of the node. The // node pointer can be either regular or // complemented. // The index field holds the name of the variable that labels the node. // The index of a variable is a permanent attribute that reflects the // order of creation. p = probs_ex[ex][index]; T = Cudd_T(node); F = Cudd_E(node); pf = Prob(F, comp); pt = Prob(T, comp); BChild0 = pf * (1 - p); BChild1 = pt * p; mVarIndex = bVar2mVar_ex[ex][index]; v = vars_ex[ex][mVarIndex]; index = v.firstBoolVar; res = BChild0 + BChild1; add_node(table, nodekey, res); return res; } } } static YAP_Bool add_var(void) { YAP_Term arg1, arg2, arg3, arg4, out, probTerm, probTerm_temp; variable *v; int i; double p, p0; arg1 = YAP_ARG1; arg2 = YAP_ARG2; arg3 = YAP_ARG3; arg4 = YAP_ARG4; nVars_ex[ex] = nVars_ex[ex] + 1; vars_ex[ex] = (variable *)realloc(vars_ex[ex], nVars_ex[ex] * sizeof(variable)); v = &vars_ex[ex][nVars_ex[ex] - 1]; v->nVal = YAP_IntOfTerm(arg1); v->nRule = YAP_IntOfTerm(arg3); v->firstBoolVar = boolVars_ex[ex]; probs_ex[ex] = (double *)realloc( probs_ex[ex], (((boolVars_ex[ex] + v->nVal - 1) * sizeof(double)))); bVar2mVar_ex[ex] = (int *)realloc( bVar2mVar_ex[ex], ((boolVars_ex[ex] + v->nVal - 1) * sizeof(int))); probTerm = arg2; p0 = 1; for (i = 0; i < v->nVal - 1; i++) { //node = Cudd_bddIthVar(mgr_ex[ex], boolVars_ex[ex] + i); p = YAP_FloatOfTerm(YAP_HeadOfTerm(probTerm)); bVar2mVar_ex[ex][boolVars_ex[ex] + i] = nVars_ex[ex] - 1; probs_ex[ex][boolVars_ex[ex] + i] = p / p0; probTerm_temp = YAP_TailOfTerm(probTerm); probTerm = probTerm_temp; p0 = p0 * (1 - p / p0); } boolVars_ex[ex] = boolVars_ex[ex] + v->nVal - 1; rules[v->nRule] = v->nVal; out = YAP_MkIntTerm((YAP_Int)nVars_ex[ex] - 1); return YAP_Unify(out, arg4); } static YAP_Bool equality(void) { YAP_Term arg1, arg2, arg3, out; int varIndex; int value; int i; variable v; DdNode *node, *tmp, *var; arg1 = YAP_ARG1; arg2 = YAP_ARG2; arg3 = YAP_ARG3; varIndex = YAP_IntOfTerm(arg1); value = YAP_IntOfTerm(arg2); v = vars_ex[ex][varIndex]; i = v.firstBoolVar; tmp = Cudd_ReadOne(mgr_ex[ex]); Cudd_Ref(tmp); node = NULL; for (i = v.firstBoolVar; i < v.firstBoolVar + value; i++) { var = Cudd_bddIthVar(mgr_ex[ex], i); node = Cudd_bddAnd(mgr_ex[ex], tmp, Cudd_Not(var)); Cudd_Ref(node); Cudd_RecursiveDeref(mgr_ex[ex], tmp); tmp = node; } if (!(value == v.nVal - 1)) { var = Cudd_bddIthVar(mgr_ex[ex], v.firstBoolVar + value); node = Cudd_bddAnd(mgr_ex[ex], tmp, var); Cudd_Ref(node); Cudd_RecursiveDeref(mgr_ex[ex], tmp); } out = YAP_MkIntTerm((YAP_Int)node); return (YAP_Unify(out, arg3)); } static YAP_Bool one(void) { YAP_Term arg, out; DdNode *node; arg = YAP_ARG1; node = Cudd_ReadOne(mgr_ex[ex]); Cudd_Ref(node); out = YAP_MkIntTerm((YAP_Int)node); return (YAP_Unify(out, arg)); } static YAP_Bool zero(void) { YAP_Term arg, out; DdNode *node; arg = YAP_ARG1; node = Cudd_ReadLogicZero(mgr_ex[ex]); Cudd_Ref(node); out = YAP_MkIntTerm((YAP_Int)node); return (YAP_Unify(out, arg)); } static YAP_Bool bdd_not(void) { YAP_Term arg1, arg2, out; DdNode *node; arg1 = YAP_ARG1; arg2 = YAP_ARG2; node = (DdNode *)YAP_IntOfTerm(arg1); node = Cudd_Not(node); out = YAP_MkIntTerm((YAP_Int)node); return (YAP_Unify(out, arg2)); } static YAP_Bool and (void) { YAP_Term arg1, arg2, arg3, out; DdNode *node1, *node2, *nodeout; arg1 = YAP_ARG1; arg2 = YAP_ARG2; arg3 = YAP_ARG3; node1 = (DdNode *)YAP_IntOfTerm(arg1); node2 = (DdNode *)YAP_IntOfTerm(arg2); nodeout = Cudd_bddAnd(mgr_ex[ex], node1, node2); Cudd_Ref(nodeout); out = YAP_MkIntTerm((YAP_Int)nodeout); return (YAP_Unify(out, arg3)); } static YAP_Bool or (void) { YAP_Term arg1, arg2, arg3, out; DdNode *node1, *node2, *nodeout; arg1 = YAP_ARG1; arg2 = YAP_ARG2; arg3 = YAP_ARG3; node1 = (DdNode *)YAP_IntOfTerm(arg1); node2 = (DdNode *)YAP_IntOfTerm(arg2); nodeout = Cudd_bddOr(mgr_ex[ex], node1, node2); Cudd_Ref(nodeout); out = YAP_MkIntTerm((YAP_Int)nodeout); return (YAP_Unify(out, arg3)); } static YAP_Bool garbage_collect(void) { YAP_Term arg1, arg2, out; YAP_Int nodes, clearCache; arg1 = YAP_ARG1; arg2 = YAP_ARG2; clearCache = YAP_IntOfTerm(arg1); nodes = (YAP_Int)cuddGarbageCollect(mgr_ex[ex], clearCache); out = YAP_MkIntTerm(nodes); return (YAP_Unify(out, arg2)); } static YAP_Bool bdd_to_add(void) { YAP_Term arg1, arg2, out; DdNode *node1, *node2; arg1 = YAP_ARG1; arg2 = YAP_ARG2; node1 = (DdNode *)YAP_IntOfTerm(arg1); node2 = Cudd_BddToAdd(mgr_ex[ex], node1); out = YAP_MkIntTerm((YAP_Int)node2); return (YAP_Unify(out, arg2)); } static YAP_Bool create_dot(void) { const char *onames[] = {"Out"}; char **inames; DdNode *array[1]; YAP_Term arg1, arg2; int i, b, index; variable v; char numberVar[10], numberBit[10], filename[1000]; FILE *file; arg1 = YAP_ARG1; arg2 = YAP_ARG2; YAP_StringToBuffer(arg2, filename, 1000); inames = (char **)malloc(sizeof(char *) * (boolVars_ex[ex])); index = 0; for (i = 0; i < nVars_ex[ex]; i++) { v = vars_ex[ex][i]; for (b = 0; b < v.nVal - 1; b++) { inames[b + index] = (char *)malloc(sizeof(char) * 20); strcpy(inames[b + index], "X"); sprintf(numberVar, "%d", i); strcat(inames[b + index], numberVar); strcat(inames[b + index], "_"); sprintf(numberBit, "%d", b); strcat(inames[b + index], numberBit); } index = index + v.nVal - 1; } array[0] = (DdNode *)YAP_IntOfTerm(arg1); file = open_file(filename, "w"); Cudd_DumpDot(mgr_ex[ex], 1, array, (const char **)inames, onames, file); fclose(file); index = 0; for (i = 0; i < nVars_ex[ex]; i++) { v = vars_ex[ex][i]; for (b = 0; b < v.nVal - 1; b++) { free(inames[b + index]); } index = index + v.nVal - 1; } free(inames); return 1; } static YAP_Bool rec_deref(void) { YAP_Term arg1; DdNode *node; arg1 = YAP_ARG1; node = (DdNode *)YAP_IntOfTerm(arg1); Cudd_RecursiveDeref(mgr_ex[ex], node); return 1; } double ProbPath(DdNode *node, int comp_par, int nex) { int index, mVarIndex, comp, pos, position, boolVarIndex; variable v; double res; double value, p, pt, pf, BChild0, BChild1, e0, e1; double *value_p, **eta_rule; DdNode *nodekey, *T, *F; comp = Cudd_IsComplement(node); comp = (comp && !comp_par) || (!comp && comp_par); if (Cudd_IsConstant(node)) { value = Cudd_V(node); if (comp) { return 0.0; } else { return 1.0; } } else { nodekey = Cudd_Regular(node); value_p = get_value(nodesB, nodekey); if (value_p != NULL) { return *value_p; } else { index = Cudd_NodeReadIndex(node); p = probs_ex[nex][index]; T = Cudd_T(node); F = Cudd_E(node); pf = ProbPath(F, comp, nex); pt = ProbPath(T, comp, nex); BChild0 = pf * (1 - p); BChild1 = pt * p; value_p = get_value(nodesF, nodekey); e0 = (*value_p) * BChild0; e1 = (*value_p) * BChild1; mVarIndex = bVar2mVar_ex[nex][index]; v = vars_ex[nex][mVarIndex]; pos = index - v.firstBoolVar; eta_rule = eta_temp[v.nRule]; eta_rule[pos][0] = eta_rule[pos][0] + e0; eta_rule[pos][1] = eta_rule[pos][1] + e1; res = BChild0 + BChild1; add_node(nodesB, nodekey, res); position = Cudd_ReadPerm(mgr_ex[nex], index); position = position + 1; boolVarIndex = Cudd_ReadInvPerm( mgr_ex[nex], position); // Returns the index of the variable currently // in the i-th position of the order. if (position < boolVars_ex[nex]) { sigma[position] = sigma[position] + e0 + e1; } if (!Cudd_IsConstant(T)) { index = Cudd_NodeReadIndex(T); position = Cudd_ReadPerm(mgr_ex[nex], index); sigma[position] = sigma[position] - e1; } if (!Cudd_IsConstant(F)) { index = Cudd_NodeReadIndex(F); position = Cudd_ReadPerm(mgr_ex[nex], index); sigma[position] = sigma[position] - e0; } return res; } } } void Forward(DdNode *root, int nex) { int i, j; if (boolVars_ex[nex]) { nodesToVisit = (DdNode ***)malloc(sizeof(DdNode **) * boolVars_ex[nex]); NnodesToVisit = (int *)malloc(sizeof(int) * boolVars_ex[nex]); nodesToVisit[0] = (DdNode **)malloc(sizeof(DdNode *)); nodesToVisit[0][0] = root; NnodesToVisit[0] = 1; for (i = 1; i < boolVars_ex[nex]; i++) { nodesToVisit[i] = NULL; NnodesToVisit[i] = 0; } add_node(nodesF, Cudd_Regular(root), 1); for (i = 0; i < boolVars_ex[nex]; i++) { for (j = 0; j < NnodesToVisit[i]; j++) UpdateForward(nodesToVisit[i][j], nex); } for (i = 0; i < boolVars_ex[nex]; i++) { free(nodesToVisit[i]); } free(nodesToVisit); free(NnodesToVisit); } else { add_node(nodesF, Cudd_Regular(root), 1); } } void UpdateForward(DdNode *node, int nex) { int index, position, mVarIndex; DdNode *T, *E, *nodereg; variable v; double *value_p, *value_p_T, *value_p_F, p; if (Cudd_IsConstant(node)) { return; } else { index = Cudd_NodeReadIndex(node); mVarIndex = bVar2mVar_ex[nex][index]; v = vars_ex[nex][mVarIndex]; p = probs_ex[nex][index]; nodereg = Cudd_Regular(node); value_p = get_value(nodesF, nodereg); if (value_p == NULL) { printf("Error\n"); return; } else { T = Cudd_T(node); E = Cudd_E(node); if (!Cudd_IsConstant(T)) { value_p_T = get_value(nodesF, T); if (value_p_T != NULL) { *value_p_T = *value_p_T + *value_p * p; } else { add_or_replace_node(nodesF, Cudd_Regular(T), *value_p * p); index = Cudd_NodeReadIndex(T); position = Cudd_ReadPerm(mgr_ex[nex], index); nodesToVisit[position] = (DdNode **)realloc( nodesToVisit[position], (NnodesToVisit[position] + 1) * sizeof(DdNode *)); nodesToVisit[position][NnodesToVisit[position]] = T; NnodesToVisit[position] = NnodesToVisit[position] + 1; } } if (!Cudd_IsConstant(E)) { value_p_F = get_value(nodesF, Cudd_Regular(E)); if (value_p_F != NULL) { *value_p_F = *value_p_F + *value_p * (1 - p); } else { add_or_replace_node(nodesF, Cudd_Regular(E), *value_p * (1 - p)); index = Cudd_NodeReadIndex(E); position = Cudd_ReadPerm(mgr_ex[nex], index); nodesToVisit[position] = (DdNode **)realloc( nodesToVisit[position], (NnodesToVisit[position] + 1) * sizeof(DdNode *)); nodesToVisit[position][NnodesToVisit[position]] = E; NnodesToVisit[position] = NnodesToVisit[position] + 1; } } return; } } } int indexMvar(DdNode *node) { int index, mVarIndex; index = Cudd_NodeReadIndex(node); mVarIndex = bVar2mVar_ex[ex][index]; return mVarIndex; } double GetOutsideExpe(DdNode *root, double ex_prob, int nex) { int i, j, mVarIndex, bVarIndex; double **eta_rule; double theta, rootProb, T = 0; sigma = (double *)malloc(boolVars_ex[nex] * sizeof(double)); for (j = 0; j < boolVars_ex[nex]; j++) { sigma[j] = 0; } for (j = 0; j < nRules; j++) { for (i = 0; i < rules[j] - 1; i++) { eta_temp[j][i][0] = 0; eta_temp[j][i][1] = 0; } } rootProb = ProbPath(root, 0, nex); if (rootProb > 0.0) { for (j = 0; j < boolVars_ex[nex]; j++) { T += sigma[j]; bVarIndex = Cudd_ReadInvPerm(mgr_ex[nex], j); if (bVarIndex == -1) { bVarIndex = j; } mVarIndex = bVar2mVar_ex[nex][bVarIndex]; eta_rule = eta_temp[vars_ex[nex][mVarIndex].nRule]; for (i = 0; i < vars_ex[nex][mVarIndex].nVal - 1; i++) { theta = probs_ex[nex][bVarIndex]; eta_rule[i][0] = eta_rule[i][0] + T * (1 - theta); eta_rule[i][1] = eta_rule[i][1] + T * theta; } } for (j = 0; j < nRules; j++) { for (i = 0; i < rules[j] - 1; i++) { eta[j][i][0] = eta[j][i][0] + eta_temp[j][i][0] * ex_prob / rootProb; eta[j][i][1] = eta[j][i][1] + eta_temp[j][i][1] * ex_prob / rootProb; } } } free(sigma); return rootProb; } void Maximization(void) { int r, i, j, e; double sum = 0; double *probs_rule, **eta_rule; for (r = 0; r < nRules; r++) { eta_rule = eta[r]; for (i = 0; i < rules[r] - 1; i++) { sum = (eta_rule[i][0] + eta_rule[i][1]); if (sum == 0.0) { arrayprob[r][i] = 0; } else arrayprob[r][i] = eta_rule[i][1] / sum; } } for (e = 0; e < ex; e++) { for (j = 0; j < nVars_ex[e]; j++) { r = vars_ex[e][j].nRule; probs_rule = arrayprob[r]; for (i = 0; i < rules[r] - 1; i++) { probs_ex[e][vars_ex[e][j].firstBoolVar + i] = probs_rule[i]; } } } } static YAP_Bool randomize(void) { int i, j, e, rule; double *theta, p0; double pmass, par; double **Theta_rules; Theta_rules = (double **)malloc(nRules * sizeof(double *)); for (j = 0; j < nRules; j++) { Theta_rules[j] = (double *)malloc(rules[j] * sizeof(double)); } for (j = 0; j < nRules; j++) { theta = Theta_rules[j]; pmass = 0; for (i = 0; i < rules[j] - 1; i++) { par = ((double)rand()) / RAND_MAX * (1 - pmass); pmass = pmass + par; theta[i] = par; } theta[rules[j] - 1] = 1 - pmass; } for (e = 0; e < ex; e++) { for (j = 0; j < nVars_ex[e]; j++) { rule = vars_ex[e][j].nRule; theta = Theta_rules[rule]; p0 = 1; for (i = 0; i < vars_ex[e][j].nVal - 1; i++) { probs_ex[e][vars_ex[e][j].firstBoolVar + i] = theta[i] / p0; p0 = p0 * (1 - theta[i] / p0); } } } for (j = 0; j < nRules; j++) { free(Theta_rules[j]); } free(Theta_rules); return 1; } static YAP_Bool EM(void) { YAP_Term arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, out1, out2, out3, nodesTerm, ruleTerm, tail, pair, compoundTerm; DdNode *node1, **nodes_ex; int r, lenNodes, i, iter; long iter1; double CLL0 = -2.2 * pow(10, 10); //-inf double CLL1 = -1.7 * pow(10, 8); //+inf double p, p0, **eta_rule, ea, er; double ratio, diff; arg1 = YAP_ARG1; arg2 = YAP_ARG2; arg3 = YAP_ARG3; arg4 = YAP_ARG4; arg5 = YAP_ARG5; arg6 = YAP_ARG6; arg7 = YAP_ARG7; arg8 = YAP_ARG8; nodesTerm = arg1; ea = YAP_FloatOfTerm(arg2); er = YAP_FloatOfTerm(arg3); lenNodes = YAP_IntOfTerm(arg4); iter = YAP_IntOfTerm(arg5); nodes_ex = (DdNode **)malloc(lenNodes * sizeof(DdNode *)); nodes_probs_ex = (double *)malloc(lenNodes * sizeof(double)); example_prob = (double *)malloc(lenNodes * sizeof(double)); for (i = 0; i < lenNodes; i++) { pair = YAP_HeadOfTerm(nodesTerm); node1 = (DdNode *)YAP_IntOfTerm(YAP_HeadOfTerm(pair)); nodes_ex[i] = node1; pair = YAP_TailOfTerm(pair); example_prob[i] = YAP_FloatOfTerm(YAP_HeadOfTerm(pair)); nodesTerm = YAP_TailOfTerm(nodesTerm); } diff = CLL1 - CLL0; ratio = diff / fabs(CLL0); if (iter == -1) iter1 = 2147000000; else iter1 = iter; while ((diff > ea) && (ratio > er) && (cycle < iter1)) { cycle++; for (r = 0; r < nRules; r++) { for (i = 0; i < rules[r] - 1; i++) { eta_rule = eta[r]; eta_rule[i][0] = 0; eta_rule[i][1] = 0; } } CLL0 = CLL1; CLL1 = Expectation(nodes_ex, lenNodes); Maximization(); diff = CLL1 - CLL0; ratio = diff / fabs(CLL0); } out2 = YAP_TermNil(); for (r = 0; r < nRules; r++) { tail = YAP_TermNil(); p0 = 1; for (i = 0; i < rules[r] - 1; i++) { p = arrayprob[r][i] * p0; tail = YAP_MkPairTerm(YAP_MkFloatTerm(p), tail); p0 = p0 * (1 - arrayprob[r][i]); } tail = YAP_MkPairTerm(YAP_MkFloatTerm(p0), tail); ruleTerm = YAP_MkIntTerm(r); compoundTerm = YAP_MkPairTerm(ruleTerm, YAP_MkPairTerm(tail, YAP_TermNil())); out2 = YAP_MkPairTerm(compoundTerm, out2); } out3 = YAP_TermNil(); for (i = 0; i < lenNodes; i++) { out3 = YAP_MkPairTerm(YAP_MkFloatTerm(nodes_probs_ex[i]), out3); } YAP_Unify(out3, arg8); out1 = YAP_MkFloatTerm(CLL1); YAP_Unify(out1, arg6); free(nodes_ex); free(example_prob); free(nodes_probs_ex); return (YAP_Unify(out2, arg7)); } static YAP_Bool Q(void) { YAP_Term arg1, arg2, arg3, arg4, out, out1, term, nodesTerm, ruleTerm, tail, pair, compoundTerm; DdNode *node1, **nodes_ex; int r, lenNodes, i; double p1, p0, **eta_rule, CLL; arg1 = YAP_ARG1; arg2 = YAP_ARG2; arg3 = YAP_ARG3; arg4 = YAP_ARG4; nodesTerm = arg1; lenNodes = YAP_IntOfTerm(arg2); nodes_ex = (DdNode **)malloc(lenNodes * sizeof(DdNode *)); example_prob = (double *)malloc(lenNodes * sizeof(double)); for (i = 0; i < lenNodes; i++) { pair = YAP_HeadOfTerm(nodesTerm); node1 = (DdNode *)YAP_IntOfTerm(YAP_HeadOfTerm(pair)); nodes_ex[i] = node1; pair = YAP_TailOfTerm(pair); example_prob[i] = YAP_FloatOfTerm(YAP_HeadOfTerm(pair)); nodesTerm = YAP_TailOfTerm(nodesTerm); } for (r = 0; r < nRules; r++) { for (i = 0; i < rules[r] - 1; i++) { eta_rule = eta[r]; eta_rule[i][0] = 0; eta_rule[i][1] = 0; } } CLL = Expectation(nodes_ex, lenNodes); out = YAP_TermNil(); for (r = 0; r < nRules; r++) { tail = YAP_TermNil(); eta_rule = eta[r]; for (i = 0; i < rules[r] - 1; i++) { p0 = eta_rule[i][0]; p1 = eta_rule[i][1]; term = YAP_MkPairTerm(YAP_MkFloatTerm(p0), YAP_MkPairTerm(YAP_MkFloatTerm(p1), YAP_TermNil())); tail = YAP_MkPairTerm(term, tail); } ruleTerm = YAP_MkIntTerm(r); compoundTerm = YAP_MkPairTerm(ruleTerm, YAP_MkPairTerm(tail, YAP_TermNil())); out = YAP_MkPairTerm(compoundTerm, out); } free(nodes_ex); free(example_prob); out1 = YAP_MkFloatTerm(CLL); YAP_Unify(out1, arg4); return (YAP_Unify(out, arg3)); } static YAP_Bool paths_to_non_zero(void) { double paths; YAP_Term arg1, arg2, out; DdNode *node; arg1 = YAP_ARG1; arg2 = YAP_ARG2; node = (DdNode *)YAP_IntOfTerm(arg1); paths = Cudd_CountPathsToNonZero(node); out = YAP_MkFloatTerm(paths); return (YAP_Unify(out, arg2)); } static YAP_Bool paths(void) { double paths; YAP_Term arg1, arg2, out; DdNode *node; arg1 = YAP_ARG1; arg2 = YAP_ARG2; node = (DdNode *)YAP_IntOfTerm(arg1); paths = Cudd_CountPath(node); out = YAP_MkFloatTerm(paths); return (YAP_Unify(out, arg2)); } static YAP_Bool dag_size(void) { int size; YAP_Term arg1, arg2, out; DdNode *node; arg1 = YAP_ARG1; arg2 = YAP_ARG2; node = (DdNode *)YAP_IntOfTerm(arg1); size = Cudd_DagSize(node); out = YAP_MkIntTerm(size); return (YAP_Unify(out, arg2)); } void init_my_predicates() /* function required by YAP for intitializing the predicates defined by a C function*/ { srand(10); YAP_UserCPredicate("init", init, 2); YAP_UserCPredicate("init_bdd", init_bdd, 0); YAP_UserCPredicate("end", end, 0); YAP_UserCPredicate("end_bdd", end_bdd, 0); YAP_UserCPredicate("add_var", add_var, 4); YAP_UserCPredicate("equality", equality, 3); YAP_UserCPredicate("and", and, 3); YAP_UserCPredicate("one", one, 1); YAP_UserCPredicate("zero", zero, 1); YAP_UserCPredicate("or", or, 3); YAP_UserCPredicate("bdd_not", bdd_not, 2); YAP_UserCPredicate("create_dot", create_dot, 2); YAP_UserCPredicate("init_test", init_test, 1); YAP_UserCPredicate("end_test", end_test, 0); YAP_UserCPredicate("ret_prob", ret_prob, 2); YAP_UserCPredicate("em", EM, 8); YAP_UserCPredicate("q", Q, 4); YAP_UserCPredicate("randomize", randomize, 0); YAP_UserCPredicate("deref", rec_deref, 1); YAP_UserCPredicate("garbage_collect", garbage_collect, 2); YAP_UserCPredicate("bdd_to_add", bdd_to_add, 2); YAP_UserCPredicate("paths_to_non_zero", paths_to_non_zero, 2); YAP_UserCPredicate("paths", paths, 2); YAP_UserCPredicate("dag_size", dag_size, 2); } FILE *open_file(char *filename, const char *mode) /* opens a file */ { FILE *fp; if ((fp = fopen(filename, mode)) == NULL) { perror(filename); exit(1); } return fp; } tablerow *init_table(int varcnt) { int i; tablerow *tab; tab = (tablerow *)malloc(sizeof(rowel) * varcnt); for (i = 0; i < varcnt; i++) { tab[i].row = NULL; tab[i].cnt = 0; } return tab; } void add_node(tablerow *tab, DdNode *node, double value) { int index = Cudd_NodeReadIndex(node); tab[index].row = (rowel *)realloc(tab[index].row, (tab[index].cnt + 1) * sizeof(rowel)); tab[index].row[tab[index].cnt].key = node; tab[index].row[tab[index].cnt].value = value; tab[index].cnt += 1; } void add_or_replace_node(tablerow *tab, DdNode *node, double value) { int i; int index = Cudd_NodeReadIndex(node); for (i = 0; i < tab[index].cnt; i++) { if (tab[index].row[i].key == node) { tab[index].row[i].value = value; return; } } tab[index].row = (rowel *)realloc(tab[index].row, (tab[index].cnt + 1) * sizeof(rowel)); tab[index].row[tab[index].cnt].key = node; tab[index].row[tab[index].cnt].value = value; tab[index].cnt += 1; } double *get_value(tablerow *tab, DdNode *node) { int i; int index = Cudd_NodeReadIndex(node); for (i = 0; i < tab[index].cnt; i++) { if (tab[index].row[i].key == node) { return &tab[index].row[i].value; } } return NULL; } void destroy_table(tablerow *tab, int varcnt) { int i; for (i = 0; i < varcnt; i++) { free(tab[i].row); } free(tab); }