⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bfagent.m

📁 人工智能的matlab程序
💻 M
📖 第 1 页 / 共 5 页
字号:
 
  static int *count[4];	// Dynamically allocated 2-d array
  static int countsize = -1;	// Current size/4 of count[]
  static int prevsize = -1;

  condbits = getInt (privateParams, "condbits");

  if (cum && condbits != prevsize)
    printf("There is an error with an agent's condbits.");
  prevsize = condbits;

// For efficiency the static array can grow but never shrink
  if (condbits > countsize) 
    {
      if (countsize > 0) free(count[0]);
      count[0] = calloc(4*condbits,sizeof(int));
      if(!count[0])
	printf("There was an error allocating space for count[0].");
      count[1] = count[0] + condbits;
      count[2] = count[1] + condbits;
      count[3] = count[2] + condbits;
      countsize = condbits;
    }
  
  (*countptr)[0] = count[0];
  (*countptr)[1] = count[1];
  (*countptr)[2] = count[2];
  (*countptr)[3] = count[3];

  if (!cum)
    for(i=0;i<condbits;i++)
      count[0][i] = count[1][i] = count[2][i] = count[3][i] = 0;

 index=[ fcastList begin: [self getZone] ];  
 for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] )
   {
     agntcond = [aForecast getConditions];
      for (i = 0; i < condbits; i++)
	{
	    count[ (int)[aForecast getConditionsbit: i]][i]++;
	}
   }
 [index drop];
 //pj: it was like this:
//    for (fptr = fcast; fptr < topfptr; fptr++) 
//      {
//        agntcond = fptr->conditions;
//        for (i = 0; i < condbits; i++)
//  	count[(int)((agntcond[WORD(i)]>>SHIFT[i])&3)][i]++;
//      }

  return condbits;
}


//pj: this method was never called anywhere in ASM-2.0

/*"Currently, this method is not called anywhere in ASM-2.2. It might
  serve some purpose, past or present, I don't know (pj:
  2001-11-26)"*/
- (int)fMoments: (double *)moment cumulative: (BOOL)cum
{
  BFCast *aForecast ;
  int i;
  int condbits;

  id index;
  
  condbits = getInt (privateParams, "condbits");
  
  if (!cum)
	for(i=0;i<6;i++)
	  moment[i] = 0;
  
 index=[ fcastList begin: [self getZone] ];  
 for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] )
   {
     moment[0] +=  [aForecast getAval];
      moment[1] += [aForecast getAval]*[aForecast getAval];
      moment[2] += [aForecast getBval];
      moment[3] += [aForecast getBval]*[aForecast getBval];
      moment[4] += [aForecast getCval];
      moment[5] += [aForecast getAval]*[aForecast getAval];
   }
 [index drop];  
  return privateParams->numfcasts;
}

//pj: this method is not called anywhere

/*"Currently, this method is not called anywhere in ASM-2.2. It might
  serve some purpose, past or present, I don't know (pj:
  2001-10-26)"*/
// ASM-2.0 documentation:
//	If the agent uses condition bits, returns a description of the
//	specified bit.  Invalid bit numbers return an explanatory message.
//	Agents that don't use condition bits return NULL.
//
- (const char *)descriptionOfBit: (int)bit
{
  if (bit < 0 || bit > getInt(privateParams,"condbits"))
    return "(Invalid condition bit)";
  else
    return [World descriptionOfBit:privateParams->bitlist[bit]];
}


/*" Genetic algorithm. It relies on the following separate methods.
(pj: 2001-11-25. I still see some room for improvement here, but the
emphasis is to eliminate all global variables and explicitly pass
return values instead.  Any values needed for computations should
either be passed explicitly or taken from someplace safe)
//
//  1. MakePool makes a list of the weakest forecasts:
//  rejectList. That is the "npool" weakest rules.
//
//  2. "nnew" new rules are created. They are put into a Swarm list
//  called newList. Their bit settings are taken from either crossover
//  (using tournament selection to get parents), or mutation.
//  "Tournament selection" means picking two candidates purely at
//  random and then choosing the one with the higher strength.  See
//  the Crossover and Mutate methods for more details about how they
//  work.
//
//  3. The nnew new rules replace weakest old ones found in step
//  1. This is done by the method "TransferFcastsFrom:To:" It pays no
//  attention to strength, but looks at similarity of the bitstrings
//  -- rather like tournament selection, we pick two candidates from
//  the rejectList at random and choose the one with the MORE similar
//  bitstring to be replaced.  This maintains more diversity.
//
//  4. Generalize looks for rules that haven't been triggered for
//  "longtime" and generalizes them by changing a randomly chosen
//  fraction "genfrac" of 0/1 bits to "don't care".  It does this
//  independently of strength to all rules in the population.
//
//  There are several private methods that take care of this
//  work. They don't show up in the public interface, but here they
//  are:

-(BFCast *)  CopyRule:(BFCast *) to From: (BFCast *) from

-(void) MakePool: rejects From: (id <Array>) list

-(BOOL) Mutate: (BFCast *) new Status: (BOOL) changed

-(BFCast *) Crossover:(BFCast *) newForecast Parent1: (BFCast *) parent1 Parent2: (BFCast *) parent2

- (void) TransferFcastsFrom: newlist To:  forecastList Replace: rejects 

- (BFCast *)  GetMort: (BFCast *) new Rejects: (id <List>) rejects

-(void) Generalize: (id) list AvgStrength: (double) avgstrength

// Parameter list:

_{npool	-- size of pool of weakest rules for possible relacement;
		   specified as a fraction of numfcasts by "poolfrac"}

_{nnew	-- number of new rules produced
		   specified as a fraction of numfcasts by "newfrac"}

_{ pcrossover -- probability of running Crossover.}

_{plinear    -- linear combination "crossover" prob.}

//  _{ prandom    -- random from each parent crossover prob.}

//  _{ pmutation  -- per bit mutation prob.}

//  _{ plong      -- long jump prob.}

//   _{pshort     -- short (neighborhood) jump prob.}

//  _{nhood      -- size of neighborhood.}

//   _{longtime	-- generalize if rule unused for this length of time}

//  _{ genfrac	-- fraction of 0/1 bits to make don't-care when generalising}
"*/
- performGA
{
  register int f;
  int  new;
  BFCast * parent1, * parent2;
 
  double ava,avb,avc,sumc;
  double madv=0.0; 
  double meanv = 0.0;
  double temp;  //for holding values needed shortly
  //pj: previously declared as globals
  int * bitlist;

  id newList = [List create: [self getZone]]; //to collect the new forecasts; 
  id rejectList = [Array create: [self getZone] setCount: getInt(privateParams,"npoolmax")];

  static double avstrength;//static inside a method has a different effect than static in a class

  ++gacount;
  currentTime = getCurrentTime();

  //??Why is lastgatime in the params at all???
  //  privateParams->lastgatime= params->lastgatime =  lastgatime = currentTime;
  lastgatime = currentTime;

  bitlist = privateParams->bitlist;

  // Find the npool weakest rules, for later use in TrnasferFcasts
  [self  MakePool: rejectList From: fcastList];


  // Compute average strength (for assignment to new rules)
  avstrength = ava = avb = avc = sumc = 0.0;
  minstrength = 1.0e20;

  for (f=0; f < privateParams->numfcasts; f++) 
    {
      BFCast * aForecast = [fcastList atOffset: f];
      double varvalue = 0;

      varvalue= [ aForecast getVariance];
      meanv += varvalue;
      if ( [aForecast  getCnt] > 0)
	{
	  if ( varvalue !=0  )
	    {
	      avstrength += [ [ fcastList atOffset: f] getStrength];
	      sumc += 1.0/ varvalue ;
	      ava +=  [ aForecast getAval ] / varvalue ;
	      avb +=  [ aForecast getBval ] / varvalue;
	      avc +=  [ aForecast getCval ] / varvalue ;
	    }
	  if( (temp = [ aForecast getStrength ]) < minstrength)
	    minstrength = temp;
	}
    }

  meanv = meanv/ privateParams->numfcasts;

  for (f=0; f < privateParams->numfcasts; f++) 
    {
      madv += fabs( [[fcastList atOffset:f] getVariance] - meanv); 
    }

  madv = madv/privateParams->numfcasts;

  //    ava /= sumc;
  //    avb /= sumc;
  //    avc /= sumc;
  /*
   * Set rule 0 (always all don't care) to inverse variance weight 
   * of the forecast parameters.  A somewhat Bayesian way for selecting 
   * the params for the unconditional forecast.  Remember, rule 0 is imune to
   * all mutations and crossovers.  It is the default rule.
   */
  [[fcastList atOffset: 0] setAval: ava/ sumc ];
  [[fcastList atOffset: 0] setBval: avb/ sumc ];
  [[fcastList atOffset: 0] setCval: avc/ sumc ];
  
  avstrength /= privateParams->numfcasts;
    
// Loop to construct nnew new rules
  for (new = 0; new < privateParams->nnew; new++) 
    {
      BOOL changed;
 
      changed = NO;
      // Loop used if we force diversity
      do 
	{
	  double varvalue, altvarvalue = 999999999;
	  BFCast * aNewForecast=nil;

	  aNewForecast = [ self createNewForecast ];
	  [aNewForecast updateSpecfactor];
	  [aNewForecast setStrength: avstrength];
   
	  //BFagent.m had equivalent of:  [aNewForecast setVariance: [aNewForecast getSpecfactor]/[aNewForecast getStrength]];
          [aNewForecast setLastactive: currentTime];
            //following bfagent.m:
	  varvalue =  privateParams->maxdev-avstrength+[aNewForecast getSpecfactor];
	  //if (varvalue < 0 ) raiseEvent(WarningMessage, "varvalue  less than zero");
	  [aNewForecast setVariance: varvalue];
	  altvarvalue = [[fcastList atOffset: 0] getVariance]- madv;
	  if ( varvalue < altvarvalue )
	  {
	    [aNewForecast setVariance: altvarvalue];
	    [aNewForecast setStrength: privateParams->maxdev - altvarvalue + [aNewForecast getSpecfactor]];
	   }
	  [aNewForecast setLastactive: currentTime];
	  
	  [newList addLast: aNewForecast]; //?? were these not initialized in original?//
          
	  // Pick first parent using touranment selection
	  //pj: ??should this operate on all or only active forecasts???
	  do
	    parent1 = [ self Tournament: fcastList ] ;
	  while (parent1 == nil);

	  // Perhaps pick second parent and do crossover; otherwise just copy
	  if (drand() < privateParams->pcrossover) 
	    {
	      do
		parent2 = [self  Tournament: fcastList];
	      while (parent2 == parent1 || parent2 == nil) ;

	      [self Crossover:  aNewForecast Parent1:  parent1 Parent2:  parent2];
	      if (aNewForecast==nil) {raiseEvent(WarningMessage,"got nil back from crossover");}
	      changed = YES;
	    }
	  else
	    {
	      [self CopyRule: aNewForecast From: parent1];
	      if(!aNewForecast)raiseEvent(WarningMessage,"got nil back from CopyRule");
	
	      changed = [self Mutate: aNewForecast Status: changed];
	    }
	  //It used to only do this if changed, but why not all??
	 
	} while (0);
      /* Replace while(0) with while(!changed) to force diversity */
    }

  // Replace nnew of the weakest old rules by the new ones

  [self  TransferFcastsFrom: newList To: fcastList Replace: rejectList];

// Generalize any rules that haven't been used for a long time
  [self Generalize: fcastList AvgStrength: avstrength ];

  // Compute average specificity
  {
    int specificity = 0;
    //note here a "raw" for loop around the fcastList. I could create an index
    //and do the swarm thing, but I leave this here to keep myself humble.

    for (f = 0; f < privateParams->numfcasts; f++) 
      {
	parent1 = [fcastList atOffset:0];
	specificity += [parent1 getSpecificity];
      }
    avspecificity = ((double) specificity)/(double)privateParams->numfcasts;

  }

  [newList deleteAll]; 
  [newList drop];

  [rejectList drop]; 

  return self;
}



/*"This is a method that copies the instance variables out of one
  forecast object into another. It copies not only the bitvector of
  monitored conditions, but also the forecast value, strength,
  variance, specFactor, specificity, and so forth.  The only deviation
  is that if the return from the original forecast's getCnt method
  (its count value) is equal to 0, then the strength of the copy is
  equal to the value of a static variable named minstrength."*/

- (BFCast *)CopyRule: (BFCast *)to From: (BFCast *)from
{
  [to setForecast: [from getForecast]];
  [to setLforecast: [from getLforecast]];
  [to setVariance: [from getVariance]];
  [to setStrength: [from getStrength]];
  [to setAval: [from getAval]];
  [to setBval: [from getBval]];
  [to setCval: [from getCval]];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -