CSDN博客

img PercyLee

由SAT问题展开说(2)[演化计算c#实现下]

发表于2003/9/20 0:59:00  1026人阅读

分类: 我的大学时代

 

                     SAT问题展开说(2)[下]

 

首先,我们看使用何种适应度函数。事实上,对于染色体组,我们好坏的评价由score来记录,如下的过程自然刻画了我们对适应度函数的设计:

private int GetScore(int i)

         {

              int score=0;

              for(int j=0;j<maxNum;j++)

              for(int k=0;k<valNum;k++)

              if(int.Parse(satGenes[i].ToString().Substring(k,1))+bSentence[j,k]==2//

                     ||int.Parse(satGenes[i].ToString().Substring(k,1))+bSentence[j,k]==-1)

                {

                     score++;

                     break;

                }

              return score;

          }

 

         public int Sort()

         {

            int iBest=0,iWorst=0;

              int bestScore=GetScore(0);//

              int worstScore=GetScore(0);

              for(int i=0;i<maxNum;i++)

              {

                score[i]=GetScore(i);

                   if(score[i]>bestScore)

                   {

                       iBest=i;

                       bestScore=score[i];

                   }

                   else if(score[i]<worstScore)

                   {

                       iWorst=i;

                       worstScore=score[i];

                   }

              }

            best=new StringBuilder(satGenes[iBest].ToString());

              worst=new StringBuilder(satGenes[iWorst].ToString());

              return bestScore;

    }

您注意到,演化策略我们采取的又不同于一般的遗传算法。当然,使用bestworst,使得演化的压力异常的大,但我们对于算子的设计是多样的,以避免早熟现象的出现。

现在是最为核心的部分,遗传算子的设计。

我们的算法中,杂交算子和变异算子都是非常多样化的。其中变异算子以Pm的概率值使一个染色体进行如下的变异:

1/3的情况进行某一位的取反变异,或以2/3的情况进行某连续两位的取反变异。

而杂交算子以Pc的概率值使两个染色体进行杂交,杂交过程如下:

从某位开始,以某个随机长度,2/3的情况进行互换子串进行杂交,1/3的情况进行异或杂交。

过程分别如下:

public void Mutation()

         {

              int mutType,start;

              string subGene;

            int i=randNum.Next(maxNum-1);

                   if(randNum.NextDouble()<=Pm)

                   {

                       mutType=randNum.Next(0,2);

                       switch(mutType)

                       {

                            case 0:

                                 start=randNum.Next(0,valNum-1);

                                 subGene=satGenes[i].ToString().Substring(start,1);

                                 if(subGene=="0")

                                     satGenes[i].Replace("0","1",start,1);

                                 else

                                     satGenes[i].Replace("1","0",start,1);

                                 break;

                            case 1:case 2:

                                 start=randNum.Next(0,valNum-2);

                                 subGene=satGenes[i].ToString().Substring(start,2);

                                switch(subGene)

                                {

                                     case "00":

                                        satGenes[i].Replace("00","11",start,2);

                                        break;

                                     case "01":

                                        satGenes[i].Replace("01","10",start,2);

                                        break;

                                     case "10":

                                        satGenes[i].Replace("10","01",start,2);

                                        break;

                                     case "11":

                                        satGenes[i].Replace("11","00",start,2);

                                        break;

                                 }

                                 break;

                            default:

                                 break;

                       }

                   }

         }

         public void Crossover()

         {

            int croType,start,length,i,j;

              string i_subGene,j_subGene;

            length=randNum.Next(5)+1;

            start=randNum.Next(0,valNum-length);

            i=randNum.Next(maxNum-1);

              j=randNum.Next(maxNum-1);

              i_subGene=satGenes[i].ToString().Substring(start,length);

              j_subGene=satGenes[j].ToString().Substring(start,length);

 

              croType=randNum.Next(2);

              switch(croType)

              {

                case 0:case 2:

                       satGenes[i].Replace(i_subGene,j_subGene,start,length);

                       satGenes[j].Replace(j_subGene,i_subGene,start,length);

                       break;

                   case 1:

                       for(int k=0;k<length;k++)

                       {

switch(int.Parse(i_subGene.Substring(k,1))

+int.Parse(j_subGene.Substring(k,1)))

                            {

                                 case 0:case 2:

satGenes[i].Replace(i_subGene.Substring(k,1),"1",start+k,1);

satGenes[j].Replace(j_subGene.Substring(k,1),"0",start+k,1);

                                     break;

                                 case 1:

satGenes[i].Replace(i_subGene.Substring(k,1),"0",start+k,1);

satGenes[j].Replace(j_subGene.Substring(k,1),"1",start+k,1);

                                     break;

                            }

                       }

                       break;

                   default:

                       break;

              }

         }

以上是SAT类的主要部分。这样算法的细节设计过程已经实现了。

下面是算法过程,以及初始化过程和其他界面过程,在类Form1中实现,另外修改演化参数的类frmSet我们就不在此介绍了(因为它不关系算法实现)。

这里是算法本身:

private void geneCompute()

         {

              int answer=0,oldAnswer=0;

              hh=DateTime.Now.Hour;

              mm=DateTime.Now.Minute;

              ss=DateTime.Now.Second;

              ms=DateTime.Now.Millisecond;

              SetTime();

              oneSAT.InitGenes();

              oldAnswer=answer=oneSAT.Sort();

              while(answer<maxNum-nilNum)

              {

                oneSAT.Mutation();

                   oneSAT.Crossover();

                   answer=oneSAT.Sort();

                   spScore.Text=strScore+answer.ToString();

                   if(answer<oldAnswer)

                   {

                        oldAnswer=answer;

                        chListBoxString.Items.Add(oneSAT.Best,true);

                   }

                  SetTime();

              }

            chListBoxString.ClearSelected();

              chListBoxString.Items.Add(oneSAT.Best,true);

              spScore.Text=strScore+answer.ToString();

    }

其中oneSATSAT类的一个对象,初始化如下:

oneSAT=new SAT(maxNum,valNum,0.8,0.02);

SetTime()是计算算法执行时间的跟踪,详细过程可见附录。而整个算法的执行,我们新创建一个线程computeGene,其过程如下:

private void threadGeneCompute()

         {

              computeGene=new Thread(new ThreadStart(geneCompute));

              computeGene.Start();

    }

这样,在类Form1中,我们可以控制这个线程computeGene来进行我们算法的数值实验了。

 

算法的参数设置如下:

l          逻辑变量规模:200 300

l          种群规模:30

l          子句数量:30

l          杂交概率:0.8

l          变异概率:0.02

l          算法的出口为最好的染色体的分数等于非空的子句数量

我们选择200300个的逻辑变量分别做了若干次实验,除去一开始就寻到结果的瞬时解答外,我们各随机选择了两个子句集与其计算结果、时间。分别为:

逻辑变量数目为200的:

其一,计算结果为:

00000000000000010000000000000000000011100000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

0000011000000000000000000000000000000000

时间为: 13s 328ms

其二,计算结果为:

00000111100100000000011110000011000000000000000110101110000000000001100000011111

00000000000100000000000000000000000000000010000000000000001100000000100000110000

0000000001000000011110000010000001111100

时间为: 57s 563ms

逻辑变量数目为300的:

其一,计算结果为:

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000111100000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000

时间为: 2s 625ms

其二,计算结果为:

00001000000000000000000000000000000000000000111000000000000000000000000000000000

00000000000000000000000100000000000000000000000000001100000000000000000000000000

00000000000000000000010000000000000011110000000000000001111100000000000000000000

000000000000000000000000000000010000000000000000000000000000

时间为: 28s 641ms

子句集合都是随机生成的,我们附录在后面供读者参考。由答案的结果来看,复杂的子句需要较多的时间,但相应于2^200 2^300的问题规模,计算速度还是可观的。

 

存在的问题

 

算法是我们上学期实现,后来由于忙于其他事情,再没有做细致的优化工作。所以现在看来,算法的可改进尝试点还是很多的。简单分析如下,而更多的提高,我们寄希望于读者。如果您对整个程序的源码有兴趣,可联系笔者,免费赠送。

首先,演化策略还比较单调。我们实际上采取的是,对一个种群,择其一按概率要求进行变异和杂交,然后排序去除最差者。没有其他的任何措施,比如好基因可以保留为一个库等。这里可以尝试改进。

算法在执行的过程中,有少量情况是,分数降低1分,但很快又还原。这表明计算不是一直向前的。而且,在计算结果趋于较好时,计算也放慢,应该想办法进行加速而有所补救。

最大的缺憾是,在最终结果出现之前,我们不能判定该集合是否是可满足的。我们只能告诉您,目前的计算结果表明,有多少子句已经可以满足,而我们希望情况越来越好。这是由演化计算的特点所决定的,改进难于实现。

算子还可以试图采取其他方案。但我们认为我们的算子设计还是较好的。

 

参考资料:

 

1)康立山,智能计算及其应用讲义,中国地质大学内部讲义,20029

(2)Harry R.Lewis/Christos H.Papadimitriou, ELEMENTS OF THE THEORY OF COMPUTATION ,清华大学出版社(影印),1999年9月

2

0 0

相关博文

我的热门文章

img
取 消
img