📄 sat.c
字号:
/* FILE : sat.c*/#include <stdio.h>#include <stdlib.h>/*包含有关时间的函数*/#include <time.h> /*mpi库函数*/#include "mpi.h" #include <math.h>/*变量数目*/#define NVARS 100/*子句数目*/#define NCLAUSES 3/*每条子句的长度*/#define LENGTH_CLAUSE 3/*fgets一行最多读入的字符数*/#define MAXLINE 60#define TRUE 1#define FALSE 0/*既不是可满足的也不是不可满足的*/#define UNCERTAIN -1/*变量值为空*/#define NOVALUE -1#define DEPTH 5/*计算pow(x,y)*/int Pow(int x, int y);#define COUNT Pow(2,DEPTH)#define TASKTAG 11 /**************/ /*主要数据结构*//**************//*变量*/struct VARIABLE{/*变量真值为1,假值为0,无值为-1*/ int value;};/*文字*/struct LITERAL{ /*取值为VAR,-VAR和NOVALUE *//* VAR取值从1到NVARS*/ int value;};/*子句*/struct CLAUSE{ struct LITERAL lit[LENGTH_CLAUSE]; int num_unassigned; /*被满足状态取值TRUE,FALSE或UNCERTAIN */int state_of_satisfied;};/*合取范式*/struct CNF{ struct VARIABLE var[NVARS]; struct CLAUSE clause[NCLAUSES]; int num_uncertain; /*结果取值为TRUE,FALSE或UNCERTAIN*/ int result;};/************//*进一步定义*//************//*测试一个子句是否可满足*/int DavisPutnam();/*当赋予一个新值时更新结构CNF*/void UpdateCNF();/*检查该CNF是否只有单一字句*/int HasUnitClause();/*检查该CNF是否有纯文字*/int HasPureLiteral();/*从输入文件读数据初始化CNF*/void InitCNF();/*从失败记号恢复CNF*/void Reverse();/*返回一个整数的绝对值*/int Abs();/*将CNF打包到一个整数缓冲*/void PackCNF();/*将一个整数缓冲释放到一个CNF*/void UnpackCNF();/*根据任务更新该CNF*/void SetValue(); /*从X中取得n位*/unsigned GetBits(); /*从根接收任务然后计算并会送结果*/void SlaveWork();/*从CNF中选变量*/void PickVars();/*检查变量是否在缓冲中*/int NotInBuf(); /*主函数*/int main(int argc,char ** argv) { struct CNF Cnf; /*合取范式CNF*/ int length=2+NVARS+NCLAUSES*(2+LENGTH_CLAUSE)+1; /*缓冲区长度*/ int buf[length]; /*LENGHT_CLAUSE*NCLAUSE缓冲区*/ MPI_Status status; /*MPI--状态*/ int i,j,myrank,size,BufResult; char* CnfFile; /*输入CNF文件名*/ FILE * in; /*处理文件*/ MPI_Init(&argc,&argv); /*MPI--初始化*/ MPI_Comm_rank(MPI_COMM_WORLD,&myrank); /*MPI--次第号*/ MPI_Comm_size(MPI_COMM_WORLD,&size); /*MPI--数目*/ /*root processor read data and initiate Cnf,then pack it to buff*/ if(myrank==0) /*进程0(主进程)*/ { if (argc<2) /*保证有两个参数*/ { printf("You forgot to enter a parametes!\n"); /*参数数目不对*/ MPI_Abort(MPI_COMM_WORLD,99); /*MPI--退出*/ } CnfFile=argv[1]; /*读取CNF文件名*/ if ((in=fopen(CnfFile,"rt"))==NULL) /*read file*/ { printf("cannot open the result file\n"); /*文件不存在或没有相应的属性*/ MPI_Abort(MPI_COMM_WORLD,99); /*MPI--退出 */ } if(myrank==0) printf("NVARS=%d NCLAUSES=%d LENGTH_CLAUSE=%d\n",NVARS,NCLAUSES,LENGTH_CLAUSE); InitCNF(&Cnf,in); /*从输入文件中读取数据并初始化CNF*/ PackCNF(Cnf,buf); /*将CNF打包到整型缓冲--便于MPI广播*/ } /*broadcast buf to all the processors*/ MPI_Barrier(MPI_COMM_WORLD); MPI_Bcast(buf,length,MPI_INT,0,MPI_COMM_WORLD); /*MPI--广播CNF包*/ MPI_Barrier(MPI_COMM_WORLD); /*if it is root processor,distribute the task and wait result from slaves*/ if ( myrank == 0) /*进程0(主进程)*/ { double start,end; start=MPI_Wtime(); /*MPI--时间(开始时间)*/ /*send the first bulk of task*/ for(i=0;i<size-1;i++) /*对每一个从进程都发送消息*/ MPI_Send(&i,1,MPI_INT,i+1,TASKTAG,MPI_COMM_WORLD); /*发送CNF信息到从进程*/ while (1) /*一直执行*/ { MPI_Recv(&BufResult,1,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&status); /*从从进程接收结果*/ if ( BufResult==TRUE ) /*SAT算法成功 */ { end=MPI_Wtime(); /*MPI--时间(结束时间)*/ i=COUNT+10; printf("\nSatisfied! time%f\n",end-start); /*运行时间*/ /*send i as the end signal*/ for(j=0;j<size-1;j++) MPI_Send(&i,1,MPI_INT,j+1,TASKTAG,MPI_COMM_WORLD); /*向从进程发送终止信号*/ break; /*退出执行*/ } else if(i>COUNT) /*SAT算法超出规模*/ { printf("\nUnsatisfied!\n"); /*SAT算法失败*/ /*send i as the terminal signal*/ for(j=0;j<size-1;j++) MPI_Send(&i,1,MPI_INT,j+1,TASKTAG,MPI_COMM_WORLD); /*向从进程发送终止信号*/ break; /*退出执行*/ } else { int dest=status.MPI_SOURCE; /*确定消息发送目的地*/ MPI_Send(&i,1,MPI_INT,dest,TASKTAG,MPI_COMM_WORLD); /*向从进程发送相应CNF包*/ i++; /*下一步操作*/ } } } else /*其它进程(从进程)*/ { unsigned BufTask; /*任务数*/ UnpackCNF(&Cnf,buf); /*将缓冲中的CNF解包*/ while(1) /*一直执行*/ { MPI_Recv(&BufTask,1,MPI_INT,0,TASKTAG,MPI_COMM_WORLD,&status); /*从进程0接受CNF包信息*/ if ( BufTask <= COUNT) /*未越界*/ SlaveWork(Cnf,BufTask,&BufResult); /*从0进程接受任务,计算,将结果返回0进程*/ else break; /*其它情况*/ } } MPI_Finalize(); /*MPI--结束*/ return(0);}/******************************************/ /*该函数从输入文件读入CNF数据并给Cnf赋值输入:in一包含CNF数据的文件输出:pCnf一个指向Cnf结构的指针*/ /******************************************/ void InitCNF(struct CNF * pCnf,FILE* in) /*从输入文件中读取数据并初始化CNF(参数:CNF式指针,处理文件)*/{ char prestr[MAXLINE]; /*文件缓存字符数组*/ int i,j,temp; for(i=0;i<NVARS;i++) /*在给定的变量数目范围(100)内*/ pCnf->var[i].value=UNCERTAIN; /*给CNF式变量赋初值(-1)*/ for (i=0;i<NCLAUSES;i++) { /*在给定的子句数目范围(350)内*/ for (j=0;j<LENGTH_CLAUSE;j++) { /*在给定的子句长度范围(3)内*/ fscanf(in,"%d",&pCnf->clause[i].lit[j].value); /*给CNF式文字赋初值*/ /* printf("%d ",&ilauses[c].lit[l]); */ } fscanf(in,"%d",&temp); /*其它读入的值存入临时变量中*/ /* printf("%d \n",temp); */ pCnf->clause[i].num_unassigned=LENGTH_CLAUSE; /*子句中未赋值数取为子句长度*/ pCnf->clause[i].state_of_satisfied=UNCERTAIN; /*子句状态取为不确定(-1)*/ } pCnf->num_uncertain=NVARS; /*CNF中未赋值数取为变量最大数目(100)*/ pCnf->result=UNCERTAIN; /*CNF结果取为不确定(-1)*/ fclose(in); /*关闭处理文件*/}/******************************************/ /*该函数计算结果是最主要的函数输入:Cnf一个CNF结构输出:DavisPutnam取值TRUE或FALSE*/ /******************************************/ int DavisPutnam(struct CNF Cnf) /*测试子句是否为SAT(参数:CNF式)*/{ int Serial;/*number of the var to be signed*/ /*待赋值的变量数*/ /*test if this Cnf has had the result*/ if (Cnf.result==TRUE) return TRUE; /*如果CNF的一部分的结果取为真,返回真*/ if (Cnf.result==FALSE) return FALSE; /*如果CNF的一部分的结果取为假,返回假*/ /*test if Cnf has unit clause*/ if (HasUnitClause(Cnf,&Serial)==TRUE ) /*CNF含有单子句*/ { Cnf.var[Abs(Serial)].value=(Serial>0)?TRUE:FALSE; /*CNF变量赋值(0或1)*/ printf("\nsingle%d",Serial); UpdateCNF(&Cnf,Abs(Serial)); /*为变量赋新值时更新CNF*/ if (Cnf.result==TRUE) return TRUE; /*如果CNF的一部分的结果取为真,返回真*/ if (Cnf.result==FALSE) return FALSE; /*如果CNF的一部分的结果取为假,返回假*/ if (DavisPutnam(Cnf)==TRUE) return TRUE; /*如果CNF的一部分测试子句后的结果取为真,返回真*/ else return FALSE; /*其它情况,返回假*/ } /*test if Cnf has pure literal*/ else if (HasPureLiteral(Cnf,&Serial)==TRUE ) /*CNF含有纯文字*/ { Cnf.var[Serial].value=TRUE; /*CNF变量赋值为真(1)*/ printf("\nPure %d",Serial); UpdateCNF(&Cnf,Serial); /*为变量赋新值时更新CNF*/ if (Cnf.result==TRUE) return TRUE; /*如果CNF的一部分的结果取为真,返回真*/ if (Cnf.result==FALSE) return FALSE; /*如果CNF的一部分的结果取为假,返回假*/ if (DavisPutnam(Cnf)==TRUE) return TRUE; /*如果CNF的一部分测试子句后的结果取为真,返回真*/ else return FALSE; /*其它情况,返回假*/ } /*pick a var without value*/ else /*CNF不只含有单个文字且不含有纯文字*/ { for(Serial=0;Serial<NVARS;Serial++) /*在给定的变量数目范围(100)内*/ if (Cnf.var[Serial].value==NOVALUE) break; /*CNF式中变量没有值,退出*/ printf("\ncommon%d",Serial); /*first assume this var is TRUE*/ Cnf.var[Serial].value=TRUE; /*CNF变量赋值为真(1)*/ UpdateCNF(&Cnf,Serial); /*为变量赋新值时更新CNF*/ if (Cnf.result==TRUE) return TRUE; /*CNF式中变量值为真(1),返回真(1)*/ else if (Cnf.result==UNCERTAIN) /*CNF式中变量值不确定*/ if (DavisPutnam(Cnf)==TRUE) return TRUE; /*如果CNF的一部分测试子句后的结果取为真,返回真*/ /*Else try that #Serial is FALSE*/ Cnf.var[Serial].value=FALSE; /*CNF变量赋值为真(1)*/ /*update Cnf when #Serial is FALSE*/ Reverse(&Cnf,Serial); /*将CNF从失败信号中恢复出来*/ if (Cnf.result==TRUE) return TRUE; /*如果CNF的一部分的结果取为真,返回真*/ if (Cnf.result==FALSE) return FALSE; /*如果CNF的一部分的结果取为假,返回假*/ if (DavisPutnam(Cnf)==TRUE) return TRUE; /*如果CNF的一部分测试子句后的结果取为真,返回真*/ return FALSE; /*其它情况,返回假(0)*/ }}/******************************************/ /*该函数检查Cnf是否有单元字句输入:Cnf一个CNF结构,Serial变量的编号输出:HasUnitClause取值为TRUE或FALSE*/ /******************************************/ int HasUnitClause(struct CNF Cnf,int *Serial) /*测试CNF是否含有单子句(参数:CNF式,指向变量的指针)*/{ int i,j,k; for (i=0;i<NCLAUSES;i++) /*在给定的子句数目范围(350)内*/ if (Cnf.clause[i].num_unassigned==1) /*子句中未赋值数为1*/ { for(j=0;j<LENGTH_CLAUSE;j++) /*在给定的子句长度范围(3)内*/ { k=Cnf.clause[i].lit[j].value; /*k暂时存放子句中相应的文字的值*/ if (Cnf.var[Abs(k)].value==NOVALUE) /*CNF中相应变量没有值*/ { *Serial=k; /*相应变量赋值*/ return TRUE; /*返回真(1)*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -