/* LPAD and CP-Logic interpreter Copyright (c) 2007, Fabrizio Riguzzi This package uses the library cudd, see http://vlsi.colorado.edu/~fabio/CUDD/ for the relative license. This file contains the functions for interfacing Yap and C The arguments of the predicate compute_prob are parsed and translated into C data structures */ #include "cplint.h" #include <math.h> #include <stdlib.h> #include <string.h> unsigned long dividend; FILE *open_file (char *filename, const char *mode); void reverse(char s[]); static int compute_prob(void); void createVars(array_t * vars, YAP_Term t,DdManager * mgr, array_t * bVar2mVar,int create_dot, char inames[1000][20]) /* adds the boolean variables to the BDD and returns an array_t containing them (array_t is defined in the util library of glu) returns also the names of the variables to be used to save the ADD in dot format */ { YAP_Term varTerm,probTerm; int varIndex,nVal,i,b; variable v; char numberVar[10],numberBit[10]; double p; b=0; while(YAP_IsPairTerm(t)) { varTerm=YAP_HeadOfTerm(t); varIndex=YAP_IntOfTerm(YAP_HeadOfTerm(varTerm)); varTerm=YAP_TailOfTerm(varTerm); nVal=YAP_IntOfTerm(YAP_HeadOfTerm(varTerm)); varTerm=YAP_TailOfTerm(varTerm); probTerm=YAP_HeadOfTerm(varTerm); v.nVal=nVal; v.nBit=(int)ceil(log(nVal)/log(2)); v.probabilities=array_alloc(double,0); v.booleanVars=array_alloc(DdNode *,0); for (i=0;i<nVal;i++) { if (create_dot) { strcpy(inames[b+i],"X"); sprintf(numberVar,"%d",varIndex); strcat(inames[b+i],numberVar); strcat(inames[b+i],"_"); sprintf(numberBit,"%d",i); strcat(inames[b+i],numberBit); } p=YAP_FloatOfTerm(YAP_HeadOfTerm(probTerm)); array_insert(double,v.probabilities,i,p); probTerm=YAP_TailOfTerm(probTerm); array_insert(DdNode *,v.booleanVars,i,Cudd_bddIthVar(mgr,b+i)); array_insert(int,bVar2mVar,b+i,varIndex); } Cudd_MakeTreeNode(mgr,b,nVal,MTR_FIXED); b=b+nVal; array_insert(variable,vars,varIndex,v); t=YAP_TailOfTerm(t); } } void createExpression(array_t * expression, YAP_Term t) /* returns the expression as an array_t of terms (cubes) starting from the prolog lists of terms each term is an array_t of factors obtained from a prolog list of factors each factor is a couple (index of variable, index of value) obtained from a prolog list containing two integers */ { YAP_Term termTerm,factorTerm; factor f; int i,j; array_t * term; i=0; while(YAP_IsPairTerm(t)) { term=array_alloc(factor,0); termTerm=YAP_HeadOfTerm(t); j=0; while(YAP_IsPairTerm(termTerm)) { factorTerm=YAP_HeadOfTerm(termTerm); f.var=YAP_IntOfTerm(YAP_HeadOfTerm(factorTerm)); f.value=YAP_IntOfTerm(YAP_HeadOfTerm(YAP_TailOfTerm(factorTerm))); array_insert(factor,term,j,f); termTerm=YAP_TailOfTerm(termTerm); j++; } array_insert(array_t *,expression,i,term); t=YAP_TailOfTerm(t); i++; } } static int compute_prob(void) /* this is the function that implements the compute_prob predicate used in pp.pl */ { YAP_Term out,arg1,arg2,arg3,arg4; array_t * variables,* expression, * bVar2mVar; DdNode * function, * add; DdManager * mgr; int nBVar,i,j,intBits,create_dot; FILE * file; DdNode * array[1]; char * onames[1]; char inames[1000][20]; char * names[1000]; GHashTable * nodes; /* hash table that associates nodes with their probability if already computed, it is defined in glib */ //Cudd_ReorderingType order; arg1=YAP_ARG1; arg2=YAP_ARG2; arg3=YAP_ARG3; arg4=YAP_ARG4; mgr=Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); variables=array_alloc(variable,0); bVar2mVar=array_alloc(int,0); create_dot=YAP_IntOfTerm(arg4); createVars(variables,arg1,mgr,bVar2mVar,create_dot,inames); //Cudd_PrintInfo(mgr,stderr); /* automatic variable reordering, default method CUDD_REORDER_SIFT used */ //printf("status %d\n",Cudd_ReorderingStatus(mgr,&order)); //printf("order %d\n",order); Cudd_AutodynEnable(mgr,CUDD_REORDER_SAME); /* Cudd_AutodynEnable(mgr, CUDD_REORDER_RANDOM_PIVOT); printf("status %d\n",Cudd_ReorderingStatus(mgr,&order)); printf("order %d\n",order); printf("%d",CUDD_REORDER_RANDOM_PIVOT); */ expression=array_alloc(array_t *,0); createExpression(expression,arg2); function=retFunction(mgr,expression,variables); /* the BDD build by retFunction is converted to an ADD (algebraic decision diagram) because it is easier to interpret and to print */ add=Cudd_BddToAdd(mgr,function); //Cudd_PrintInfo(mgr,stderr); if (create_dot) /* if specified by the user, a dot file for the BDD is written to cpl.dot */ { nBVar=array_n(bVar2mVar); for(i=0;i<nBVar;i++) names[i]=inames[i]; array[0]=add; onames[0]="Out"; file = open_file("cpl.dot", "w"); Cudd_DumpDot(mgr,1,array,names,onames,file); fclose(file); } nodes=g_hash_table_new(my_hash,my_equal); intBits=sizeof(unsigned int)*8; /* dividend is a global variable used by my_hash it is equal to an unsigned int with binary representation 11..1 */ dividend=1; for(j=1;j<intBits;j++) { dividend=(dividend<<1)+1; } out=YAP_MkFloatTerm(Prob(add,variables,bVar2mVar,nodes)); g_hash_table_foreach (nodes,dealloc,NULL); g_hash_table_destroy(nodes); Cudd_Quit(mgr); array_free(variables); array_free(bVar2mVar); array_free(expression); return(YAP_Unify(out,arg3)); } /* int compare(char *a, char *b) { int aval,bval; aval=(int) *((DdNode **)a); aval=(int) *((DdNode **)b); if (aval<bval) return -1; else if (aval>bval) return 1; else return 0; } */ void init_my_predicates() /* function required by YAP for intitializing the predicates defined by a C function*/ { YAP_UserCPredicate("compute_prob",compute_prob,4); } 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; } void reverse(char s[]) /* reverses a string */ { int i,c,j; for (i=0,j=strlen(s)-1;i<j;i++,j--) { c=s[i]; s[i]=s[j]; s[j]=c; } } gint my_equal(gconstpointer v,gconstpointer v2) /* function used by GHashTable to compare two keys */ { DdNode *a,*b; a=*(DdNode **)v; b=*(DdNode **)v2; return (a==b); } guint my_hash(gconstpointer key) /* function used by GHashTable to hash a key */ { unsigned int h; h=(unsigned int)((unsigned long) *((DdNode **)key) % dividend); return h; } void dealloc(gpointer key,gpointer value,gpointer user_data) { free(key); free(value); }