www.pudn.com > asm_java.zip > Agent.java


package asm;

import java.util.Vector;
/**
 * Title:        Artificial Stock Market
 * Description:  人工模拟股市(来源:SFI的Swarm版本)的Java版本
 * Copyright:    Copyright (c) 2003
 * Company:      http://agents.yeah.net
 * @author jake
 * @version 1.0
 */

public class Agent {
  static double minstrength;//最小的规则适应度
  public double demand;	/*对股票的需求量" bid or -offer"*/
  public double profit;	/*当期赢得的利润" exp-weighted moving average "*/
  public double wealth;	/*总财富" total agent wealth "*/
  public double position;/*股票的持有量" total shares of stock "*/
  public double cash;/*当期的现金量" total agent cash position "*/
  public double initialcash;//初始时刻的现金
  public double minholding;//最小的持股量
  public double mincash;//最小现金量
  public double intrate;//利率
  public double intratep1;//利率+1
  public double price;//当前的股票价格 price is maintained by World
  public double dividend;//当前的股息 dividend is maintained by World
  public int myID;
  int currentTime; /*当前时间"The agent regularly checks with Swarm to see what time it is"*/
  int lastgatime;	/*上一次运行遗传算法的时间" last time period when the GeneticAlgorithm was run"*/
  double avspecificity; /*平均特异性'average specificity of active forecasts"*/
  double forecast;       /*对price+dividend的预测值"prediction of stock price: (trialprice+dividend)*pdcoeff + offset."*/
  double lforecast; /*上一次的预测值"lagged forecast: forecast value from previous period"*/
  double global_mean; /*"price+dividend"*/
  double realDeviation;  /*预测与现实的差" ftarget-lforecast: how far off was the agent's forecast?"*/
  double variance;   /*一个加权平均数公式:bv*variance + av*deviation*deviation"an Exp.Weighted MA of the agent's historical variance: Combine the old variance with deviation^squared, as in:  bv*variance + av*deviation*deviation"*/
  double pdcoeff;   /*预测系数" coefficient used in predicting stock price, recalculated each period in prepareForTrading"*/
  double offset;    /*预测系数" coefficient used in predicting stock price, recalculated each period in prepareForTrading"*/
  double divisor;   /*计算股票需求量的一个系数" a coefficient used to calculate demand for stock. It is a proportion (lambda) of forecastvar (basically, accuracy of forecasts)"*/
  int gacount;     /*运行过遗传算法的次数" how many times has the Genetic Algorithm been used?"*/
  AgentParam privateParams;     /*关于agent参数的一个集合"BFParams object holds parameters of this object"*/

  Vector fcastList;        /*预测规则的列表"A Swarm Array, holding the forecasts that the agent might use"*/

  Vector activeList;       /*激活的预测规则列表"A Swarm list containing a subset of all forecasts"*/
  Vector oldActiveList;    /*激活的预测规则列表的拷贝"A copy of the activeList from the previous time step"*/
  Vector History;         //关于agent的历史纪录
  World  worldForAgent;   //当前的世界状态和编码
  AsmModel local;         //对于AsmModel的一个拷贝


/*"This tells BFagents where they should look to get the default
  parameters. it should give the agent an object from the BFParams
  class."*/
void setBFParameterObject(AgentParam x){
    privateParams=x;
}

/*" Sets a world for an agent.  It is a class method as it is used in
both class and instance methods in BFagent."*/
void setWorld(World aWorld){
  worldForAgent = aWorld;
}


/*"  Sets the IVAR intrate and uses that to calculate intratep1 (intrate + 1)."*/
void setintrate(double rate){
  //设定利率
  intrate = rate;
  intratep1 = intrate + 1.0;
}


/*" Sets the borrowing and short selling constraints, i.e., the
  //      values can be negative. It sets values of the IVARS minholding and mincash"*/
void setminHolding(double holding,double minimumcash){
  minholding = holding;
  mincash = minimumcash;
}


/*" Sets the initial stock holdings of each agent. It is the
 * designated initializer.  Most agent classes will have additional
 * initialization, but should do [super setInitialHoldings] to run
 * this first. It will initialize instance variables common to all
 * agents, setting profit,wealth, and position equal to 0, and it sets
 * the variable cash equal to initialcash "*/
void setInitialHoldings(){
  //几个参数的初始化
  profit = 0.0;
  wealth = 0.0;
  cash = initialcash;
  position = 0.0;
}

/*" Sets an instance variable of agent, price, to the current price
  which is controlled by the object known as "world". Please note this
  assumes world is already set. "*/
void getPriceFromWorld(){
  price = worldForAgent.getPrice();
}

/*"Sets an instance variable of agent, dividend, to the current dividend. That information is retrieved from the object known as "world"."*/
void getDividendFromWorld(){
  dividend = worldForAgent.getDividend();
}

void creditEarningsAndPayTaxes()
/*"Sent to each agent after a dividend is declared.  The agents
 * receive the dividend for each unit of stock they hold.  Their cash"
 * in the fixed asset account also receives its interest.  Then taxes
 * are charged on the previous total wealth, at a rate that balances
 * the interest on cash -- so if the agent had everything in cash it
 * would end up at the same place.

 * This is done in each period after the new dividend is declared.  It is
 * not normally overridden by subclases.  The taxes are assessed on the
 * previous wealth at a rate so that there's no net effect on an agent
 * with position = 0.
 *
 * In principle we do:
 *	wealth = cash + price*position;			// previous wealth
 *	cash += intrate * cash + position*dividend;	// earnings
 *	cash -= wealth*intrate;				// taxes
 * but we cut directly to the cash:
 *	cash -= (price*intrate - dividend)*position
" */
{
//对每个agent进行征税和分红
  getPriceFromWorld();
  getDividendFromWorld();

// Update cash
  cash -= (price*intrate - dividend)*position;
  if (cash < mincash)cash = mincash;

// Update wealth
  wealth = cash + price*position;
}


double constrainDemand(double slope[],double trialprice)
/*" Method used by agents to constrain their demand according to the
 * mincash and minholding constraints.

 * It checks "demand" against the
 * mincash and minholding constraints and clips it if necessary, then
 * also setting *slope.  For use within subclass implementations of
 * getDemandAndSlope: forPrice:.  Used only by agents that work with
 * the Slope Specialist."*/

{
//检查交宜人的需求量是否过量。如果是买入,则察看他的现金是否还够,否则察看他能否卖出那么多股票。
// If buying, we check to see if we're within borrowing limits,
// remembering to handle the problem of negative dividends  -
// cash might already be less than the min.  In that case we
// freeze the trader.
  if (demand > 0.0) {
    if (demand*trialprice > (cash - mincash))
      {
	if (cash - mincash > 0.0) {
	  demand = (cash - mincash)/trialprice;
	  slope[0] = -demand/trialprice;
	}
	else
	  {
	    demand = 0.0;
	    slope[0] = 0.0;
	  }
      }
  }

// If selling, we check to make sure we have enough stock to sell
  else if (demand < 0.0 && demand + position < minholding)
    {
      demand = minholding - position;
      slope[0] = 0.0;
    }
  return demand;
}

/*"initForecasts. Creates BFCast objects (forecasts) and puts them
  into an array called fCastList.  These are the "meat" of this
  agent's functionality, as they are repeatedly updated, improved, and
  tested in the remainder of the class.  Please note each BFagent has
  a copy of the default params object called privateParams.  It can be
  used to set individualized values of settings in BFParams for each
  agent. That would allow true diversity! I don't see how that diversity
  would be allowed for in the ASM-2.0."*/
void initForecasts(){
  //初始化自己所有的预测规则
  int  sumspecificity = 0;
  int i;
  Forecast aForecast=new Forecast(privateParams.condbits);
  int numfcasts;
// Initialize our instance variables

  //all instances of BFagent can use the same BFParams object.
  //ASM-2.0 was written that way, something like:
  // privateParams= params;

  // That seemed fraught with danger, with all instances having
  // read/write access to a global parameter object, so now I'm
  // creating a copy that each agent can have and individualize.
  //privateParams = [params copy: [self getZone]];

  //If you want to customize privateParams, this is the spot!

  numfcasts = privateParams.numfcasts;

  //fcastList=[Array create: [self getZone] setCount: numfcasts];

  avspecificity = 0.0;
  gacount = 0;

  variance = privateParams.initvar;
  getPriceFromWorld();
  getDividendFromWorld();
  global_mean = price + dividend;
  forecast = lforecast = global_mean;


  // Initialize the forecasts, put them into Swarm Array

  //keep the 0'th forecast in a  "know nothing" condition
  //[fcastList atOffset: 0 put: [self createNewForecast]];
  //fcastList.addElement(new Forecast(worldForAgent.NWORLDBITS));
  //create rest of forecasts with random conditions
  //初始化每条规则,主要让规则的if部分随机取0,1,2,then部分在允许范围内取值。
    for(i = 0; i < numfcasts; i++){
      aForecast=createNewForecast();
      setConditionsRandomly(aForecast);
      fcastList.addElement(aForecast); //put aForecast into Swarm array "fcastlist"
     }

/* Compute average specificity */

  //pj: Here is the proper way to iterate over Swarm collections
  //计算平均特异度
  int size=fcastList.size();
  for(i=0;i= privateParams.firstgatime && Math.random() < privateParams.gaprob)
    {
      local.localasm.setStatus("正在执行遗传算法");
      performGA();
      activeList.removeAllElements();
    }

  //this saves a copy of the agent's last as lforecast.
  lforecast = forecast;

  //得到世界当前的编码
  myworld = collectWorldData();

  //根据编码激活规则
  updateActiveList(myworld);

  maxstrength = -1e50;
  bestForecast = null;
  nactive = 0;
  mincount = privateParams.mincount;

  //在激活的规则列表中找出适应度最高的规则
  int size=activeList.size();
  for(int i=0;i= mincount){
	  double strength=aForecast.strength;
	  ++nactive;
	  if (strength > maxstrength||(strength<-1e50&&maxstrength==-1e50)){
	      maxstrength = strength;
	      bestForecast= aForecast;
          }
	}
    }

  //如果有规则被激活,则选择最好的规则作为参数
  if (nactive>=1)  // meaning that at least some forecasts are active
    {
      pdcoeff = bestForecast.a;
      offset = bestForecast.b*dividend + bestForecast.c;
      if(privateParams.individual==1){
       forecastvar = bestForecast.variance;
      }else{
        forecastvar = variance;
      }
    }
  else  //如果没有规则被激活 meaning "nactive" zero, no forecasts are active
    {
      countsum = 0.0;
      pdcoeff = 0.0;
      double pdcoeff1=0;
      double offset1=0;
      offset = 0.0;
      mincount = privateParams.mincount;

      //针对每条规则计算加权平均的预测系数
      size=fcastList.size();
      for ( int i=0;i= 0){
              weight=aForecast.strength;
	      countsum += weight;
              offset += aForecast.b*dividend + aForecast.c*weight;
	      pdcoeff += aForecast.a*weight;
              offset1+=aForecast.b*dividend + aForecast.c;
              pdcoeff1+=aForecast.a;
	    }
	  forecastvar = variance;
      }
      if (countsum > 0.0){
	      offset /= countsum;
	      pdcoeff /= countsum;
      }else{
              countsum=size;
              offset =0;//offset1/countsum;
	      pdcoeff =0;//pdcoeff1/countsum;
      }
    }

  //更新需求效用函数中的分母。
  double addvar=privateParams.addvar;
  divisor = privateParams.lambda*forecastvar+addvar;
  //divisor=Math.sqrt(divisor);
}

/*"A forecast has a set of conditions it is watching. These are packed
tight in a BitVector. We need the world data about the status of those
conditions packed the same way, in order to make quick checks to find
out if the world conditions are matched by the BitVector's
conditions. This method creates a BitVector to match the conditions
that are being monitored by the agent's forecasts.  This requires the
use of the design assumption that all of an agent's forecasts have the
same bitlist."*/
String collectWorldData()
{
//收集世界的信息及其编码
  int i,n,nworldbits;
  String world;
  String myRealWorld=null;
  world="";
  nworldbits =worldForAgent.getNumWorldBits();
  myRealWorld=worldForAgent.getRealWorld();
  world=myRealWorld;
  return world;
}


/*"This is the main inner loop over forecasts. Go through the list
  of active forecasts, compare how they did against the world.  Notice
  the switch that checks to see how big the bitvector (condwords) is
  before proceeding.  At one time, this gave a significant
  speedup. The original sfsm authors say 'Its ugly, but it
  works. Don't mess with it!'  (pj: I've messed with it, and don't
  notice much of a speed effect on modern computers with modern
  compilers :> My alternative implementation is commented out inside
  this method)"*/
void updateActiveList(String worldvalues)
{
  //根据世界当前的编码,更新激活规则链表
  Forecast aForecast;
  copyList(activeList,oldActiveList);
  activeList.removeAllElements();
  //作一份拷贝
  int size=oldActiveList.size();
  for( int i=0;i0) or offer (if <0) using
* best (or mean) linear forecast chosen by -prepareForTrading. The
* forecast is given by

   forecast = pdcoeff*(trialprice+dividend) + offset

* where pdcoeff and offset are set by -prepareForTrading.

A risk aversion computation gives a target holding, and its
derivative ("slope") with respect to price.  The slope is calculated
as the linear approximated response of a change in price on the
traders' demand at time t, based on the change in the forecast
according to the currently active linear rule. "*/

{
  //得到需求和边界需求

  //先得到预测的价格量
  forecast = (trialprice + dividend)*pdcoeff + offset;
  //根据公式x=(a(p+d)+b-p(1+r))/divisor计算需求量
  if (forecast >= 0.0){
      demand = -((trialprice*intratep1 - forecast)/divisor + position);
      slope[0] = (pdcoeff-intratep1)/divisor;
  }else{
      forecast = 0.0;
      demand = - (trialprice*intratep1/divisor + position);
      slope[0] = -intratep1/divisor;
    }
  //限定需求量的范围。
  // Clip bid or offer at "maxbid".  This is done to avoid problems when
  // the variance of the forecast becomes very small, thought it's not clear
  // that this is the best solution.
  if (demand > privateParams.maxbid)
    {
      demand = privateParams.maxbid;
      slope[0] = 0.0;
    }
  else if (demand < -privateParams.maxbid)
    {
      demand = -privateParams.maxbid;
      slope[0] = 0.0;
    }

  constrainDemand(slope,trialprice);
  return demand;
}



/*" Now update the variance and strength of all the forecasts that
  were active in the previous period, since now we know how they
  performed. This method causes an update of price/dividend
  information from the world, then it measures how far off each
  forecast was and puts the square of that "deviance" measure into the
  forecast with the forecast's setVariance: method. Each forecast in
  the active list is told to update its forecast.  It also updates the
  instance variable variance, which is calculated here as an
  exponentially weignted moving average of that forecast's
  squared-error (variance).  Inside the code of updatePerformance,
  there is a description of the strength formula that is used, and how
  the formula now matches the formula used in the original sfsm,
  rather than ASM-2.0. "*/

void updatePerformance()
{
  //对规则的表现参数进行更新
  //pj: register struct BF_fcast *fptr;
  Forecast  aForecast;
  double deviation, ftarget, tauv, a, b, c, av, bv, maxdev;

  // Precompute things for speed
  tauv = privateParams.tauv;
  a = 1.0/tauv;
  b = 1.0-a;
  // special rates for variance
  // We often want this to be different from tauv
  // PARAM:  100. should be a parameter  BL
  av = 0.7;//1.0/(double)100.0;
  bv = 1.0-av;

    /* fixed variance if tauv at max */
  if (tauv == 100000)
    {
      a = 0.0;
      b = 1.0;
      av = 0.0;
      bv = 1.0;
    }
    //最大的离差
  maxdev = privateParams.maxdev;
  double maxprice=local.asmModelParams.maxprice;

// Update global mean (p+d) and our variance
//预测目标如下计算
  getPriceFromWorld();
  ftarget = price + dividend;


// Update global mean (p+d) and our variance

  realDeviation = deviation = ftarget - lforecast;
  if (Math.abs(deviation) > maxdev) deviation = maxdev;

  //重新计算p+d的数值,采用加权平均的方式
  global_mean = b*global_mean + a*ftarget;
  // Use default for initial variances - for stability at startup
  currentTime = getCurrentTime( );
  if (currentTime < 1)
    variance = privateParams.initvar;
  else
    variance = bv*variance + av*deviation*deviation*maxdev*maxdev/(maxprice*maxprice);//计算方差

  int size=activeList.size();
  for( int i=0;i 0){
      size=oldActiveList.size();//index = [ activeList begin: [self getZone]];
      for( int i=0;i maxdev) deviation = maxdev;
	  if (aForecast.c> tauv)
	    aForecast.variance = b*aForecast.variance + a*deviation;
	  else{
	      c = 1.0/(double) (1.0 +aForecast.count);  //??bfagent had no 1+ here ??
	      aForecast.variance=(1.0 - c)*aForecast.variance + c*deviation;
          }
          //更新规则的强度
	  aForecast.strength=privateParams.maxdev-aForecast.variance+aForecast.specfactor;
	}

    }
  }
}

/*"Returns the absolute value of realDeviation"*/
double getDeviation(){
  return Math.abs(realDeviation);
}


int nbits()
{
  return privateParams.condbits;
}

int nrules()
{
  return privateParams.numfcasts;
}

int lastgatime()
{
  return lastgatime;
}


/*" 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 ) 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 ) 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}
"*/
void performGA()
{
  //执行遗传算法
  int f;
  int new1;
  Forecast 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[];
  Vector newList=new Vector();//盛放新的规则
  Vector rejectList=new Vector();//盛放淘汰掉的规则
  int rejectIndex[];//淘汰规则的索引
  rejectIndex=new int[privateParams.npool+1];
  double avstrength;//规则的平均适应度static inside a method has a different effect than static in a class
  ++gacount;//遗传算法运行的次数
  currentTime = getCurrentTime();//当前的方针周期
  lastgatime = currentTime;

  //制作一个池子,成方那些被淘汰的规则列表
  MakePool(rejectList,rejectIndex,fcastList);
  local.localasm.setStatus("正在执行遗传算法:计算平均值");

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

  //计算平均系数a,b,c,平均方差,最小适应度
  for (f=0; f < privateParams.numfcasts; f++){
      Forecast aForecast =(Forecast)fcastList.elementAt(f);// [fcastList atOffset: f];
      double varvalue = 0;

      varvalue= aForecast.variance;
      meanv += varvalue;
      if ( aForecast.count >= 0){
	  if ( varvalue !=0  ){
	      avstrength += aForecast.strength;// atOffset: f] getStrength];
	      sumc += 1.0/ varvalue ;
	      ava +=  aForecast.a  / varvalue ;
	      avb +=  aForecast.b / varvalue;
	      avc +=  aForecast.c / varvalue ;
	    }
	  if( aForecast.strength < minstrength)
	    minstrength = aForecast.strength;
	}
    }

  meanv = meanv/ privateParams.numfcasts;

  for (f=0; f < privateParams.numfcasts; f++){
      Forecast temp1=(Forecast)fcastList.elementAt(f);
      madv += Math.abs( temp1.variance - meanv);
    }
  madv = madv/privateParams.numfcasts;
  avstrength /= privateParams.numfcasts;

// Loop to construct nnew new rules
  local.localasm.setStatus("正在执行遗传算法:正在进行遗传操作");
  for (new1 = 0; new1 < privateParams.nnew; new1++){
      boolean changed;//因为遗传操作是按照概率进行的,所以,做一个标志是否进行了遗传操作

      changed = false;
      // Loop used if we force diversity
      do{
	  double varvalue, altvarvalue = 999999999;
	  //制作一个新的规则,并让他的各个变量取平均值
          Forecast aNewForecast=new Forecast(privateParams.condbits);

	  aNewForecast = createNewForecast();
	  aNewForecast.updateSpecfactor();
	  aNewForecast.strength=avstrength;

	  //BFagent.m had equivalent of:  [aNewForecast setVariance: [aNewForecast getSpecfactor]/[aNewForecast getStrength]];
          aNewForecast.lastactive=currentTime;
	  varvalue =  privateParams.maxdev-avstrength+aNewForecast.specfactor;
	  //if (varvalue < 0 ) raiseEvent(WarningMessage, "varvalue  less than zero");
	  aNewForecast.variance=varvalue;
          Forecast temp1=(Forecast)fcastList.elementAt(0);
	  altvarvalue = temp1.variance- madv;
	  if ( varvalue < altvarvalue ){
	    aNewForecast.variance= altvarvalue;
	    aNewForecast.strength=privateParams.maxdev - altvarvalue + aNewForecast.specfactor;
	   }
	  aNewForecast.lastactive=currentTime;

          //选择父亲,选择算法由Tournament进行操作
	  do
	    parent1 = Tournament(fcastList);
	  while (parent1 == null);

	  // 进行交叉操作
	  if (Math.random() < privateParams.pcrossover){
              //选择母亲
	      do
		parent2 = Tournament(fcastList);
	      while (parent2 == parent1 || parent2 == null) ;
                //开始交叉
	       aNewForecast=Crossover(aNewForecast,parent1,parent2);
	        changed = true;
	    }else{
              //否则把父亲规则拷贝给新的规则
	      aNewForecast=CopyRule(parent1);
              //进行变异操作
	      changed = Mutate(aNewForecast,changed);
	    }
	  //将新规则加入列表中
	  newList.addElement(aNewForecast); //?? were these not initialized in original?//

	} while (!changed);
      /* Replace while(0) with while(!changed) to force diversity */
    }

  // Replace nnew of the weakest old rules by the new ones
  local.localasm.setStatus("正在执行遗传算法:用新规则淘汰旧规则");
  TransferFcastsFrom(newList,fcastList,rejectList,rejectIndex);
  local.localasm.setStatus("正在执行遗传算法:强迫没有被激活的规则产生多样性");
  Generalize(fcastList,avstrength);
  local.localasm.setStatus("正在执行遗传算法:重新计算平均值");  // 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 = (Forecast)fcastList.elementAt(f);
	specificity += parent1.specificity;
      }
    avspecificity = ((double) specificity)/(double)privateParams.numfcasts;

  local.localasm.setStatus("执行遗传算法结束");

  newList.removeAllElements();
  rejectList.removeAllElements();
}



/*"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."*/

Forecast CopyRule(Forecast from){
  Forecast to=new Forecast(privateParams.condbits);
  to.forecast=from.forecast;
  to.lforecast=from.lforecast;
  to.variance=from.variance;
  to.strength=from.strength;
  to.a=from.a;
  to.b=from.b;
  to.c=from.c;
  to.specfactor=from.specfactor;
  to.lastactive=from.lastactive;
  to.specificity=from.specificity;
  to.conditions=from.conditions;
  to.count=from.count;
  if (from.count==0)to.strength=minstrength;
  return to;
}


/*"Given a list of forecasts, find the worst ones and put them into a
pool of rejects. This method requires 2 inputs, the name of the reject
list (actually, a Swarm Array) and the Array of forecasts. "*/
void MakePool(Vector rejects,int indexes[],Vector list){
  //制作一个池子,找出最弱适应度的若干规则
  int top;
  int i,j = 0 ;
  Forecast aForecast;
  Forecast aReject=new Forecast(privateParams.condbits);

  top = -1;
  //pj: why not just start at 1 so we never worry about putting forecast 0 into the mix?

  //下面制作这个淘汰值,并且要按照适应度值从小到大进行排列
  //找出npool条最弱适应度的规则
  for ( i=0; i < privateParams.npool; i++ ){
      //从原始列表中顺序取出规则
      aForecast=(Forecast)list.elementAt(i);
      for ( j=top;  j >= 0 ; j--){//对现在的拒绝列表中的元素进行循环
          aReject=(Forecast)(rejects.elementAt(j));
          int k=indexes[j];
          //如果发现拒绝的规则的强度大于当前顺序取出的规则,则把这条拒绝规则往后移一位
          //并且更新indexes里面的数值,因为该书组记录的是被拒绝规则在原始规则列表中的索引值
          if(aReject!=null&&aForecast.strength < aReject.strength){
            if(rejects.size()>j+1){
              rejects.removeElementAt(j+1);
            }
            rejects.insertElementAt(aReject,j+1);
            indexes[j+1]=k;
          }else{
            break;
          }
      }  //note j decrements at the end of this loop

      //把拒绝列表中的第一个元素用新的规则替换
      if(rejects.size()>j+1){
         rejects.removeElementAt(j+1);
      }
      //将循环到的新规则加入拒绝列表中
      rejects.insertElementAt(aForecast,j+1);
      indexes[j+1]=i;
      top++;
    }

  //对list列表中剩下的规则进行循环,执行上面过程类似的操作
  int t=i;
  for ( i=t; i < privateParams.numfcasts; i++){
      aForecast=(Forecast)list.elementAt(i);
      Forecast temp1=(Forecast)rejects.elementAt(top);
      if ( aForecast.strength< temp1.strength)	{
	  for ( j = top-1; j >= 0; j--){
              aReject=(Forecast)rejects.elementAt(j);
              int k=indexes[j];
              if(aReject!=null&&aForecast.strength < aReject.strength){
                if(rejects.size()>j+1){
                    //indexes.removeElementAt(j+1);
                    rejects.removeElementAt(j+1);
                }
                indexes[j+1]=k;
                rejects.insertElementAt(aReject,j+1);
              }else{
                break;
              }
	    }
	}
      if(rejects.size()>j+1){
            //indexes.removeElementAt(j+1);
            rejects.removeElementAt(j+1);
      }
      indexes[j+1]=i;
      rejects.insertElementAt(aForecast,j+1);
      //aForecast=(Forecast)rejects.elementAt(j+1);
    }
  //pj:note: we are not checking to see if forecast 0 is in here
}




/*------------------------------------------------------*/
/*	Tournament					*/
/*------------------------------------------------------*/
Forecast Tournament(Vector list){
  //Tournament选择算子,随机的从列表中选择两个规则,返回适应度比较大的那个。
  int  numfcasts=list.size();
  Forecast candidate1 = (Forecast)list.elementAt((int)(Math.random()*numfcasts));
  Forecast candidate2;

  do
    candidate2 = (Forecast)list.elementAt((int)(Math.random()*numfcasts));
  while (candidate2 == candidate1);
  if (candidate1.strength> candidate2.strength)
    return candidate1;
  else
    return candidate2;
}




/*------------------------------------------------------*/
/*	Mutate						*/
/*------------------------------------------------------*/
boolean Mutate(Forecast new1,boolean changed)
  /*变异操作*/

{
  int bit;
  double choice, temp;
  boolean bitchanged = false;
  bitchanged =changed;
  if (privateParams.pmutation > 0){
      for (bit = 0; bit < privateParams.condbits; bit++){
	  if (Math.random() < privateParams.pmutation){
              //执行变异操作,如果当前变异位值为0或1,则变异位相反的数或者2
	      if ( Integer.parseInt(new1.getConditionsbit(bit))<2){
		  if ((int)(Math.random()*3)> 1){
		      new1.maskConditionsbit(bit);
          	      new1.decrSpecificity();
	          } else{
		    new1.switchConditionsbit(bit);
		    bitchanged = changed = true;
                  }
              }else if ((int)(Math.random()*3)> 0){//否则变异为0或者1
		  new1.setConditionsbit(bit,String.valueOf((int)(Math.random()*2)));
		  new1.incrSpecificity();
		  bitchanged = changed = true;
              }
          }
      }
  }

  /* mutate p+d coefficient */
  //对系数的变异
  choice = Math.random();
  //如果是大变异,则新规则的a为随机在区间中取值,否则用参数nhood进行变异,也就是取一个邻域
  if (choice < privateParams.plong){
      new1.a=privateParams.a_min + privateParams.a_range*Math.random();
      changed = true;
  }else if (choice < privateParams.plong + privateParams.pshort){
      /* short jump  = uniform within fraction nhood of range */
      temp = new1.a + privateParams.a_range*privateParams.nhood*(Math.random()*2-1);
      if(temp > privateParams.a_max){
         new1.a=privateParams.a_max;
      }else{
         if(temp < privateParams.a_min){
            new1.a=privateParams.a_min;
          }else{
            new1.a=temp;
          }
      }
      changed = true;
  }

  /* mutate dividend coefficient */
  //变异系数b,方法同上
  choice = Math.random();
  if (choice < privateParams.plong){
      /* long jump = uniform distribution between min and max */
      new1.b= privateParams.b_min + privateParams.b_range*Math.random();
      changed = true;
    }else if (choice < privateParams.plong + privateParams.pshort){
      /* short jump  = uniform within fraction nhood of range */
      temp = new1.b+privateParams.b_range*privateParams.nhood*(Math.random()*2-1);
      if(temp > privateParams.b_max){
         new1.b=privateParams.b_max;
      }else{
          if(temp < privateParams.b_min){
            new1.b=privateParams.b_min;
          }else{
            new1.b=temp;
          }
      }
      changed = true;
    }
  /* else leave alone */

  /* mutate constant term */
  //对c进行变异,方法同上
  choice = Math.random();
  if (choice < privateParams.plong){
      /* long jump = uniform distribution between min and max */
      new1.c= privateParams.c_min + privateParams.c_range*Math.random();
      changed = true;
  }else if (choice < privateParams.plong + privateParams.pshort){
      /* short jump  = uniform within fraction nhood of range */
      temp = new1.c + privateParams.c_range*privateParams.nhood*(Math.random()*2-1);
      if(temp > privateParams.c_max){
          new1.c=privateParams.c_max;
      }else{
          if(temp < privateParams.c_min){
            new1.c=privateParams.c_min;
          }else{
            new1.c=temp;
          }
      }
      changed = true;
  }
  /* else leave alone */

  new1.count=0;
  //更新特定度
  if (changed){
      new1.updateSpecfactor();
  }
  return(changed);
}



/*------------------------------------------------------*/
/*	Crossover					*/
/*------------------------------------------------------*/
Forecast Crossover(Forecast newForecast,Forecast parent1,Forecast parent2)
  /*交叉操作,if部分是位串的交叉,then部分是系数的线性或者其他组合
     * On the condition bits, Crossover() uses uniform crossover -- each
     * bit is chosen randomly from one parent or the other.
     * For the real-valued forecasting parameters, Crossover() does
     * one of three things:
     * 1. Choose a linear combination of the parents' parameters,
     *    weighted by strength.
     * 2. Choose each parameter randomly from each parent.
     * 3. Choose one of the parents' parameters (all from one or all
     *    from the other).
     * Method 1 is chosen with probability plinear, method 2 with
     * probability prandom, method 3 with probability 1-plinear-prandom.
     */
{
  /* Uniform crossover of condition bits */
  int bit;
  // unsigned int *cond1, *cond2, *newcond;
  int word;
  double weight1, weight2, choice;

  newForecast.specificity=0;
  /*for (word = 0; word condwords; word++)
    newForecast.setConditionsBit(word,0);*/
  //将父母的if部分的位串进行随机混合
  for (bit = 0; bit < privateParams.condbits; bit++){
     if ((int)(Math.random()*2)== 0){
	  String value=parent1.getConditionsbit(bit);
	  newForecast.setConditionsbit(bit,value);
	  if (Integer.parseInt(value)<2) newForecast.incrSpecificity();
      }else{
	  String value= parent2.getConditionsbit(bit);
	  newForecast.setConditionsbit(bit,value);
	  if (Integer.parseInt(value)<2) newForecast.incrSpecificity();
      }
  }

  /* Select one crossover method for the forecasting parameters */
  //按照不同的概率选择交叉系数的方法
  choice = Math.random();
  if (choice < privateParams.plinear){
      /* Crossover method 1 -- linear combination */
      //线性加权求和
      if(parent1.strength + parent2.strength!=0){
        weight1 = parent1.strength / (parent1.strength + parent2.strength);
      }else{
        weight1=0.5;
      }

      weight2 = 1.0-weight1;

      newForecast.a=weight1*parent1.a+weight2*parent2.a;
      newForecast.b=weight1*parent1.b+weight2*parent2.b;
      newForecast.c=weight1*parent1.c+weight2*parent2.c;
    }else if (choice < privateParams.plinear + privateParams.prandom){
      /* Crossover method 2 -- randomly from each parent */
      //随机的从父母中选择系数
      if((int)(Math.random()*2)==0)
	newForecast.a=parent1.a; else newForecast.a=parent2.a;
      if((int)(Math.random()*2)==0)
	newForecast.b=parent1.b; else newForecast.b=parent2.b;
      if((int)(Math.random()*2)==0)
	newForecast.c=parent1.c; else newForecast.c=parent2.c;
    }else{
      /* Crossover method 3 -- all from one parent */
      //从父母的系数中进行直接拷贝
      if ((int)(Math.random()*2)==0){
	  newForecast.a=parent1.a;
          newForecast.b=parent1.b;
	  newForecast.c=parent1.c;
      }else{
	  newForecast.a=parent2.a ;
	  newForecast.b=parent2.b;
	  newForecast.c=parent2.c;
      }
    }
  {  //This is just error checking!
    String newcond;
    int specificity=0;
    newForecast.count=0;	// call it new in any case

    newForecast.updateSpecfactor();

    newForecast.strength=0.5*(parent1.strength + parent2.strength);


 //pj: next steps are purely diagnostic!
   newcond = newForecast.conditions;

    for (bit = 0; bit < privateParams.condbits; bit++)
    if ( newcond.charAt(bit) != '2' ){
	  specificity++;
    }
  }
  return newForecast;
}


/*------------------------------------------------------*/
/*	TransferFcasts					*/
/*------------------------------------------------------*/
void TransferFcastsFrom(Vector newlist,Vector fcastlist, Vector rejects,int indexes[]){
  //用新规则代替旧规则,选择的标准是在pool中找到最接近新规则那个规则并替换掉
  Forecast aForecast;
  Forecast toDieForecast;

  int size=newlist.size();
  for ( int i=0;i privateParams.longtime){
          //如果该条规则已经有足够长时间没有被激活了,就进行变异,比例按照aForecast.specificity*privateParams.genfrac计算

	  changed = false;
          j = (int)(Math.ceil(aForecast.specificity*privateParams.genfrac));
	  while(j>0&&aForecast.specificity>0){
	      bit =(int)(Math.random()*privateParams.condbits);
	      if ( Integer.parseInt(aForecast.getConditionsbit(bit))<2){
		  aForecast.maskConditionsbit(bit);
		  aForecast.decrSpecificity();
		  changed = true;
		  j--;
		}
	    }
	  if (changed){
	      double varvalue;
	      aForecast.count=0;
	      aForecast.lastactive=currentTime;
	      aForecast.updateSpecfactor();
	      varvalue = privateParams.maxdev - avgstrength + aForecast.specfactor;
	      if (varvalue >0 ){
		aForecast.variance=varvalue;
	      }
	      aForecast.strength=avgstrength;
	    }
	}
    }
}



/*"This is a general utility method for Swarm lists. It removes all
  objects form the "outputList" and copies the elements from list into
  it.  It does not actually destroy any elements from either list, it
  just updates references."*/
void copyList(Vector list,Vector outputList){
  outputList.removeAllElements();
  int size=list.size();
  for( int i=0;iWorldVariants.cycleMax){
    History.removeElementAt(0);
  }
}
}

//预测规则类,分为两部分:即0,1,2组成的if部分的位串和a,b,c系数组成的then部分,
//他们都能根据a(p+d)+b*d+c进行p+d的预测
class Forecast{
  public double forecast;	/*预测值" this forecast of return"*/
  public double lforecast;	/*上一期的预测值" previous forecast"*/
  public double variance;	/*方差" variance of this forecast"*/
  public double strength;      /*强度(适应度)"strength=maxdev - variance +specfactor. This was the original sfsm specification, not the ASM-2.0 specification"*/
  public double a;		/*" (price + dividend) coefficient"*/
  public double b;		/*" dividend coefficient "*/
  public double c;		/*" constant term"*/
  public double specfactor;	/*特异度系数,对总强度做出贡献" specificty=(condbits - nnulls - specificity)* bitcost. "*/
  public double bitcost; /*一个权数" cost of using bits in forecasts"*/

  public String conditions; /*规则的if部分" a BitVector object that holds records on which conditions in the world are being monitored by this forecast object"*/
  public int lastactive;  /*上一次被激活的时间" last time period in which this forecast was active"*/
  public int specificity; /*" specificity "*/
  public int count; /*总共被激活的次数" number of times this forecast has been active"*/
  public int condbits; /*if部分的位数"number of bits of information monitored by this forecast"*/
  public int nnulls; /*无用位的位数"number of 'unused' bits that remain in the allocated vector after the 'condbits' bits have been used"*/

  /*"A BFCast is an object that holds all the forcecasting components of
  a bit forecast.  That means it has a BitVector (a thing called
  "conditions" in the code that keeps track of which world bits are
  being monitored) as well as other coefficients that are used to
  calculate forecasts. It has instance variables that record when the
  rule was last used, how many times it has been used, how accururate
  its predictions are, and so forth."*/


public Forecast(int cond){
  condbits=cond;
  if (condbits==0 ){return;}
  forecast= 0.0;
  count = 0;
  lastactive=1;
  specificity = 0;
  variance = 999999999;
  conditions="";
  if(condbits<=60){
    //为了加速
    conditions="22222222222222222222222222222222222222222222222222222222222222";
  }else{
    for(int i=0;i