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

📄 asmmodelswarm.m

📁 人工智能的matlab程序
💻 M
字号:
#import "ASMModelSwarm.h"
#import <simtools.h>
#import "Output.h"
#import "BFParams.h"
#import "BFCast.h"
#import <random.h>

#include <misc.h>


@implementation ASMModelSwarm
/*"The ASMModelSwarm is where the substantive work of the simulation
  is orchestrated.  The ASMModelSwarm object is told where to get its
  parameters, and then it buildsObjects (agents, markets, etc), it
  builds up a phony history of the market, and then it schedules the
  market opening and gives the agents a chance to buy and sell.
  
 This model presents an interesting scheduling challenge. We want to
  generate 501 periods of history that agents can refer to when they
  make decisions.  The warmUp schedule is a repeating schedule, and we
  want its actions done 501 times, and when that is finished, we want
  the periodSchedule to begin at time 0, the starting time of actual
  agent involvement.  When I looked at the original, I shuddered at
  the complexity of it.  I thought to myself, there must be a simpler
  way to do this [grin :)], and it turns out there is.  Now, in case
  you are comparing the new code against the old code, understand that
  the old ASM-2.0 way was like this.  First, the warmUp schedule is
  created.  Then a second nonrepeating schedule is created, called
  "startupSchedule."  At time 0 in the model, that startupSchedule
  controls the first action, and the action it executes is a method
  that causes the warmUp schedule to run 501 steps of prehistory. I
  don't know why they had 501 steps, but they did.  That's the warmUp
  method.  The warmUp method gets that done by creating a temporary
  Swarm class without any context (activateIn: nil) and then
  activating the startupSchedule in there, so it runs "doWarmupStep"
  501 steps, but none of the 501 steps count against time in the
  larger context of the model.


  As of ASM-2.2, I have gotten rid of that complicated setup. Instead
  of creating the phony swarm and activating the warmup schedule
  inside it, I created a method in ASMModelSwarm.m that carries out
  one time step's worth of warmup.  And then I dumped 501
  createActionTo methods on the startup schedule that execute the
  required startup steps.  I've verified the results are numerically
  identical to the original model.  And the scheduling is much easier
  to understand.

  After the warmUp, then an ActionGroup called "periodActions" comes
  to the forefront.  The periodSchedule is a repeating schedule, which
  causes the periodActions to happen at every time step in the larger
  model.

  In ASM-2.0, there was another initial schedule called
  initPeriodSchedule.  After looking at it for a long time, I
  concluded it was doing nothing necessary, it was basically just
  running the periodActions at time 0 only. We might as well just
  schedule that action at time 0 in the startupSchedule. I have
  verified that the model runs exactly the same (numerically
  identical).  Now, as noted below, I think this step is logically
  unnecessary, but removing it changes the numerical path of the
  simulation, so I'm leaving it in for comparison.  "*/

- createEnd
{
  modelTime=0; 

  return [super createEnd];
}


/*"This is very vital.  When the ASMModelSwarm is created, it needs to
 * be told where to find many constants that determine how agents are
 * created. This passes handles of objects that have the required
 * data."*/
- setParamsModel: (ASMModelParams *) modelParams BF: (BFParams *) bfp 
{
  bfParams = bfp;
  asmModelParams=modelParams;
  fprintf(stderr,"Param object %d ",asmModelParams->numBFagents);
  return self;
}

- setOutputObject: (Output *) obj
{
  output = obj;
  return self;
}


/*" Returns the number of BFagents,  which is held in asmModelParams"*/
- (int) getNumBFagents
{
  return asmModelParams->numBFagents;
}

/*" Returns the initialcash value, which is held in asmModelParams"*/
- (double) getInitialCash
{
  return asmModelParams->initialcash;
}
  
/*" Returns a list that contains all the agents"*/
- getAgentList
{
  return agentList;
}

/*" Returns a handle of the world object, the place where historical
  price/dividend information is maintained.  It is also the place
  where the BFagents can retrieve information in bit string form."*/
- (World *)getWorld
{
  if (world == nil) printf("Empty world!");
  return world;
}

/*" Return a pointer to the Specialist object"*/
- (Specialist *)getSpecialist
{
  return specialist;
}

/*" Return a pointer to an object of the Output class. Sometimes it is
  necessary for other classes to find out who the output record keeper
  is and send that class a message."*/
- (Output *)getOutput
{
  return output;
}


/*"
  Returns the integer time-step of the current simulation. 
  "*/
- (long int)getModelTime
{
  return modelTime;
}


/*"The value of the randomSeed that starts the simulation will remain
  fixed, unless you change it by using this method"*/
- setBatchRandomSeed: (int)newSeed
{
  asmModelParams->randomSeed = newSeed;
  return self;
}

/*"Build and initialize objects"*/
- buildObjects      
{
  int i;

  //  fprintf(stderr, "numBFagents  %d \n intrate  %f \n baseline %f \n eta %f \n initvar %f \n", asmModelParams->numBFagents,asmModelParams->intrate, asmModelParams->baseline, asmModelParams->eta, asmModelParams->initvar);

  if(asmModelParams->randomSeed != 0) 
    [randomGenerator setStateFromSeed: asmModelParams->randomSeed];
  //pj: note I'm making this like other swarm apps. Same each time, new seeds only if precautions taken.

 
  /* Initialize the dividend, specialist, and world (order is crucial) */
  dividendProcess = [Dividend createBegin: [self getZone]];
  [dividendProcess initNormal];
  [dividendProcess setBaseline: asmModelParams->baseline];
  [dividendProcess setmindividend: asmModelParams->mindividend];
  [dividendProcess setmaxdividend: asmModelParams->maxdividend];
  [dividendProcess setAmplitude: asmModelParams->amplitude];
  [dividendProcess setPeriod:asmModelParams-> period];
  [dividendProcess setDerivedParams];
  dividendProcess = [dividendProcess createEnd];

  world = [World createBegin: [self getZone]];
  [world setintrate: asmModelParams->intrate];
  [world setExponentialMAs: asmModelParams->exponentialMAs];
  [world initWithBaseline:asmModelParams-> baseline];
  world = [world createEnd];

  specialist = [Specialist createBegin: [self getZone]];
  [specialist setMaxPrice: asmModelParams->maxprice];
  [specialist setMinPrice: asmModelParams-> minprice];
  [specialist setTaup:asmModelParams-> taup];
  [specialist setSPtype: asmModelParams-> sptype];
  [specialist setMaxIterations: asmModelParams-> maxiterations];
  [specialist setMinExcess: asmModelParams->minexcess];
  [specialist setETA: asmModelParams-> eta];
  [specialist setREA: asmModelParams-> rea];
  [specialist setREB: asmModelParams->reb];
  specialist = [specialist createEnd];
 
  [output setWorld: world];
  [output setSpecialist: specialist];
  
  /* Initialize the agent modules and create the agents */
  agentList = [List create: [self getZone]];  //create list for agents


  /* Set class variables */
  [BFagent init];
  [BFagent setBFParameterObject: bfParams];
  [BFagent setWorld: world];
    
  //nowObject create the agents themselves
  for (i = 0; i < asmModelParams->numBFagents; i++) 
    {
      BFagent * agent;
      agent = [BFagent createBegin: [self getZone]];
      [agent setID: i];
      [agent setintrate: asmModelParams->intrate];
      [agent setminHolding: asmModelParams->minholding   minCash:asmModelParams-> mincash];
      [agent setInitialCash: asmModelParams->initialcash];
      [agent setInitialHoldings];
      [agent setPosition: asmModelParams->initholding];
      [agent initForecasts];
      agent = [agent createEnd];
      [agentList addLast: agent];
    }

  return self;
}

/*"This triggers a writing of the model parameters, for record keeping."*/
- writeParams
{
   if (asmModelParams != nil && bfParams != nil)
    [output writeParams: asmModelParams BFAgent: bfParams Time: modelTime];
  return self;
}


/*"Create the model actions, separating into two different action
 * groups, the warmup period and the actual period.  Note that time is
 * not calculated by a t counter but internally within Swarm.  Time is
 * recovered by the getTime message"*/

- buildActions
{
  [super buildActions];

 //Define the actual period's actions.  
  periodActions = [ActionGroup create: [self getZone]];

//Set the new dividend.  This method is defined below. 
  [periodActions createActionTo:     self
		 message: M(periodStepDividend)];

// Tell agents to credit their earnings and pay taxes
  [periodActions createActionForEach:    agentList     
		 message: M(creditEarningsAndPayTaxes)];

// Update world -- moving averages, bits, etc
  [periodActions createActionTo:     world     
		 message: M(updateWorld)];

// Tell BFagents to get ready for trading (they may run GAs here)
  [periodActions createActionForEach:     agentList
		   message: M(prepareForTrading)];

// Do the trading -- agents make bids/offers at one or more trial prices
// and price is set.  This is defined below.
  [periodActions createActionTo:     self
		 message: M(periodStepPrice)];

// Complete the trades -- change agents' position, cash, and profit
  [periodActions createActionTo:     specialist     
		 message: M(completeTrades:Market:):agentList:world];

// Tell the agents to update their performance
  [periodActions createActionForEach: agentList     
		 message: M(updatePerformance)];

// Create the model schedule


  startupSchedule = [Schedule create: [self getZone] setAutoDrop: YES];


 
  //force the system to do 501 "warmup steps" at the beginning of the
  //startup Schedule.  Note that, since these phony steps are just
  //handled by telling classes to do the required steps, nothing fancy
  //is required.
  {
    int i;
    for (i = 0; i < 502; i++)
      [startupSchedule at: 0 createActionTo: self message:M(doWarmupStep)];
  }
 

  //pj: 2001-10-30. This was in the original model, I don't know why, but
  //taking it out changes the numerical results, so I'm leaving it in,
  //even though it is not logically necessary.
  [startupSchedule at: 0 createAction: periodActions];
    

  periodSchedule = [Schedule createBegin: [self getZone]];
  [periodSchedule setRepeatInterval: 1];
  periodSchedule = [periodSchedule createEnd];
  [periodSchedule at: 0 createAction: periodActions];

  return self;
}

/*"Ask the dividend object for a draw from the dividend distribution, then tell the world about it. Tell the world to do an update of to respond to the dividend. Then calculate the price the divident implies and insert it into the world"*/
-doWarmupStep
{
  double div = [dividendProcess dividend];
  [world setDividend: div];
  [world updateWorld];
  [world setPrice: (div/(double)asmModelParams->intrate )];
  return self;
}

/*" Have the dividendProcess calculate a new dividend. Then tell the
  world about the dividendProcess output.  Also this increment the
  modelTime variable"*/
- periodStepDividend 
{
  modelTime++;
  [world setDividend: [dividendProcess dividend]];
  return self;
}

/*"Have the Specialist perform the trading process. Then tell the world about the price that resulted from the Specialist's action."*/
- periodStepPrice 
{
  [world setPrice: [specialist performTrading: agentList Market: world]];
  return self;
}

/*"The activities of the ASMModelSwarm are brought into time-sync with
  higher level Swarm activities. Basically, each time the higher level
  takes a step, this one will too, and the higher one won't step again
  until this one is finished with its turn."*/
- activateIn: (id)swarmContext
{
  [super activateIn: swarmContext];
  [startupSchedule activateIn: self];
  [periodSchedule activateIn: self];
  return [self getSwarmActivity];
}

- (void)drop
{
  [dividendProcess drop];
  [world drop];
  [specialist drop];
  [output drop];
  [super drop];
}

@end











⌨️ 快捷键说明

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