diff -rc ASM-2.2.1/Agent.h ASM-2.4/Agent.h *** ASM-2.2.1/Agent.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/Agent.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 1,51 **** ! #import //Agent is a SwarmObject ! #import ! #import "World.h" ! ! @interface Agent:SwarmObject ! { ! @public ! double demand; /*" bid or -offer"*/ ! double profit; /*" exp-weighted moving average "*/ ! double wealth; /*" total agent wealth "*/ ! double position; /*" total shares of stock "*/ ! double cash; /*" total agent cash position "*/ ! double initialcash; ! double minholding; ! double mincash; ! double intrate; ! double intratep1; ! double price; // price is maintained by World ! double dividend; // dividend is maintained by World ! int myID; ! } ! ! ! +setWorld: (World *)aWorld; ! ! -setID: (int)iD; ! -setPosition: (double)aDouble; ! -setintrate: (double)rate; ! -setminHolding: (double)holding minCash: (double)minimumcash; ! -setInitialCash: (double)initcash; ! -setInitialHoldings; ! -getPriceFromWorld; ! -getDividendFromWorld; ! ! -creditEarningsAndPayTaxes; ! -(double)constrainDemand: (double *)slope : (double)trialprice; ! -(double)getAgentPosition; ! -(double)getWealth; ! -(double)getCash; ! ! //Methods specified by each agent type ! -prepareForTrading; ! -(double)getDemandAndSlope: (double *)slope forPrice: (double)trialprce; ! -updatePerformance; ! ! @end ! ! ! ! ! --- 1,63 ---- ! #import //Agent is a SwarmObject ! #import ! #import ! #import "World.h" ! ! ! @interface Agent:SwarmObject ! { ! @public ! double demand; /*" bid or -offer"*/ ! double profit; /*" exp-weighted moving average "*/ ! double wealth; /*" total agent wealth "*/ ! double position; /*" total shares of stock "*/ ! double cash; /*" total agent cash position "*/ ! double initialcash; ! double minholding; ! double mincash; ! double intrate; ! double intratep1; ! double price; // price is maintained by World ! double dividend; // dividend is maintained by World ! int myID; ! @protected ! id agentList; ! } ! ! ! + setWorld: (World *)aWorld; ! ! - setID: (int)iD; ! - (int)getID; ! - setPosition: (double)aDouble; ! - setintrate: (double)rate; ! - setminHolding: (double)holding minCash: (double)minimumcash; ! - setInitialCash: (double)initcash; ! - setInitialHoldings; ! - (void)setAgentList: aList; ! ! - getPriceFromWorld; ! - getDividendFromWorld; ! ! - creditEarningsAndPayTaxes; ! - (double)constrainDemand: (double *)slope : (double)trialprice; ! - (double)getAgentPosition; ! - (double)getWealth; ! - (double)getCash; ! ! //Methods specified by each agent type ! - prepareForTrading; ! - (double)getDemandAndSlope: (double *)slope forPrice: (double)trialprce; ! - updatePerformance; ! ! - (void)bareLispOutDeep: stream; ! ! - (void)lispSaveStream: stream Double: (const char*) aName Value: (double)val; ! ! - (void)lispSaveStream: stream Integer: (const char*) aName Value: (int)val; ! @end ! ! ! ! ! diff -rc ASM-2.2.1/Agent.m ASM-2.4/Agent.m *** ASM-2.2.1/Agent.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/Agent.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 1,247 **** ! // CLASS METHODS ! // +setWorld: (World *)aWorld ! ! ! ! #import "Agent.h" ! ! World * worldForAgent; ! ! @implementation Agent ! /*" This is the abstract superclass of all agent classes; all agent classes ! // must be direct or indirect descendants of this one. ! "*/ ! ! ! /*" Sets a world for an agent. It is a class method as it is used in ! both class and instance methods in BFagent."*/ ! +setWorld: (World *)aWorld; ! { ! worldForAgent = aWorld; ! return self; ! } ! ! /*" Gives an integer name to an agent during creation. Sometimes it ! * helps with debugging to have a unique id for each agent "*/ ! -setID: (int)iD ! { ! myID = iD; ! return self; ! } ! ! ! /*" Sets the agent's position (holding) to "aDouble"."*/ ! -setPosition: (double)aDouble ! { ! position = aDouble; ! return self; ! } ! ! ! /*" Sets the IVAR intrate and uses that to calculate intratep1 (intrate + 1)."*/ ! -setintrate: (double)rate; ! { ! intrate = rate; ! intratep1 = intrate + 1.0; ! return self; ! } ! ! ! /*" Sets the borrowing and short selling constraints, i.e., the ! // values can be negative. It sets values of the IVARS minholding and mincash"*/ ! -setminHolding: (double)holding minCash: (double)minimumcash ! { ! minholding = holding; ! mincash = minimumcash; ! return self; ! } ! ! /*" Sets the initial cash holdings of each agent."*/ ! -setInitialCash: (double)initcash; ! { ! initialcash = initcash; ! return self; ! } ! ! /*" 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 "*/ ! -setInitialHoldings ! { ! profit = 0.0; ! wealth = 0.0; ! cash = initialcash; ! position = 0.0; ! ! return self; ! } ! ! /*" 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. "*/ ! -getPriceFromWorld ! { ! price = [worldForAgent getPrice]; ! return self; ! } ! ! /*"Sets an instance variable of agent, dividend, to the current dividend. That information is retrieved from the object known as "world"."*/ ! -getDividendFromWorld ! { ! dividend = [worldForAgent getDividend]; ! return self; ! } ! ! ! -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 ! " */ ! { ! [self getPriceFromWorld]; ! [self getDividendFromWorld]; ! ! // Update cash ! cash -= (price*intrate - dividend)*position; ! if (cash < mincash) ! cash = mincash; ! ! // Update wealth ! wealth = cash + price*position; ! ! return self; ! } ! ! ! -(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 = -demand/trialprice; ! } ! else ! { ! demand = 0.0; ! *slope = 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; ! } ! return demand; ! } ! ! /*" Return the agent's current position "*/ ! -(double)getAgentPosition ! { ! return position; ! } ! ! /*" Return the agent's current wealth "*/ ! -(double)getWealth ! { ! return wealth; ! } ! ! ! /*" Return the agent's current cash level "*/ ! -(double)getCash ! { ! return cash; ! } ! ! /*"Sent to each enabled agent at the start of each trading period, ! * before the first -getDemandAndSlope:forPrice: message for that ! * agent. The class method +prepareForTrading: is sent to each type ! * before any of these messages. This probably should have some ! * subclassMustImplement code here, because the default code does ! * nothing. It must be overridden"*/ ! -prepareForTrading ! { ! return self; ! } ! ! /*" This message is sent to each agent during bidding to ask for its bid ! // (demand > 0) or offer (demand < 0) at price p. The agent may ! // also return a value for d(demand)/d(price) through "slope", ! // but this is not required; *slope may be left unchanged. This ! // method may be called one or more times in each period, ! // depending on the specialist method. The last such call is at ! // the final trading price. The -prepareForTrading message is ! // sent to each agent before the first such call in each period. ! // Note that agents without demand functions return zero slope, ! // but the Slope specialist is never used with these agents. ! // ! // There is no default for this method in the Agent class; the ! // agent subclasses MUST provide it."*/ ! ! -(double)getDemandAndSlope: (double *)slope forPrice: (double)p ! { ! [self subclassResponsibility:_cmd]; ! return 0.0; // not reached ! } ! ! /*"Sent to each enabled agent at the end of each period to tell it to ! // update its performance meaures, forecasts, etc. The default code ! does nothing, this method must be specified by each agent type. ! Probably needs a subclass responsibility statement"*/ ! -updatePerformance ! { ! return self; ! } ! ! ! @end ! ! ! ! ! ! ! ! ! ! ! ! ! --- 1,296 ---- ! // CLASS METHODS ! // +setWorld: (World *)aWorld ! ! ! ! #import "Agent.h" ! ! World * worldForAgent; ! ! @implementation Agent ! /*" This is the abstract superclass of all agent classes; all agent ! // classes must be direct or indirect descendants of this one. "*/ ! ! ! /*" Sets a world for an agent. It is a class method as it is used in ! both class and instance methods in BFagent."*/ ! +setWorld: (World *)aWorld; ! { ! worldForAgent = aWorld; ! return self; ! } ! ! /*" Gives an integer name to an agent during creation. Sometimes it ! * helps with debugging to have a unique id for each agent "*/ ! -setID: (int)iD ! { ! myID = iD; ! return self; ! } ! ! /* Returns the integer name of the agent 10.09.2002 BaT*/ ! -(int)getID; ! { ! return myID; ! } ! ! ! /*" Sets the agent's position (holding) to "aDouble"."*/ ! -setPosition: (double)aDouble ! { ! position = aDouble; ! return self; ! } ! ! ! /*" Sets the IVAR intrate and uses that to calculate intratep1 (intrate + 1)."*/ ! -setintrate: (double)rate; ! { ! intrate = rate; ! intratep1 = intrate + 1.0; ! return self; ! } ! ! ! /*" Sets the borrowing and short selling constraints, i.e., the ! // values can be negative. It sets values of the IVARS minholding and mincash"*/ ! -setminHolding: (double)holding minCash: (double)minimumcash ! { ! minholding = holding; ! mincash = minimumcash; ! return self; ! } ! ! /*" Sets the initial cash holdings of each agent."*/ ! -setInitialCash: (double)initcash; ! { ! initialcash = initcash; ! return self; ! } ! ! /*" 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 "*/ ! -setInitialHoldings ! { ! profit = 0.0; ! wealth = 0.0; ! cash = initialcash; ! position = 0.0; ! ! return self; ! } ! ! ! - (void)setAgentList: aList ! { ! agentList = aList; ! } ! ! ! /*" 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. "*/ ! -getPriceFromWorld ! { ! price = [worldForAgent getPrice]; ! return self; ! } ! ! /*"Sets an instance variable of agent, dividend, to the current dividend. That information is retrieved from the object known as "world"."*/ ! -getDividendFromWorld ! { ! dividend = [worldForAgent getDividend]; ! return self; ! } ! ! ! -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 ! " */ ! { ! [self getPriceFromWorld]; ! [self getDividendFromWorld]; ! ! // Update cash ! cash -= (price*intrate - dividend)*position; ! if (cash < mincash) ! cash = mincash; ! ! // Update wealth ! wealth = cash + price*position; ! ! return self; ! } ! ! ! -(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 = -demand/trialprice; ! } ! else ! { ! demand = 0.0; ! *slope = 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; ! } ! return demand; ! } ! ! /*" Return the agent's current position "*/ ! -(double)getAgentPosition ! { ! return position; ! } ! ! /*" Return the agent's current wealth "*/ ! -(double)getWealth ! { ! return wealth; ! } ! ! ! /*" Return the agent's current cash level "*/ ! -(double)getCash ! { ! return cash; ! } ! ! /*"Sent to each enabled agent at the start of each trading period, ! * before the first -getDemandAndSlope:forPrice: message for that ! * agent. The class method +prepareForTrading: is sent to each type ! * before any of these messages. This probably should have some ! * subclassMustImplement code here, because the default code does ! * nothing. It must be overridden"*/ ! -prepareForTrading ! { ! return self; ! } ! ! /*" This message is sent to each agent during bidding to ask for its bid ! // (demand > 0) or offer (demand < 0) at price p. The agent may ! // also return a value for d(demand)/d(price) through "slope", ! // but this is not required; *slope may be left unchanged. This ! // method may be called one or more times in each period, ! // depending on the specialist method. The last such call is at ! // the final trading price. The -prepareForTrading message is ! // sent to each agent before the first such call in each period. ! // Note that agents without demand functions return zero slope, ! // but the Slope specialist is never used with these agents. ! // ! // There is no default for this method in the Agent class; the ! // agent subclasses MUST provide it."*/ ! ! -(double)getDemandAndSlope: (double *)slope forPrice: (double)p ! { ! [self subclassResponsibility:_cmd]; ! return 0.0; // not reached ! } ! ! /*"Sent to each enabled agent at the end of each period to tell it to ! // update its performance meaures, forecasts, etc. The default code ! does nothing, this method must be specified by each agent type. ! Probably needs a subclass responsibility statement"*/ ! -updatePerformance ! { ! return self; ! } ! ! ! - (void)lispSaveStream: stream Double: (const char*) aName Value: (double)val ! { ! [stream catSeparator]; ! [stream catKeyword: aName ]; ! [stream catSeparator]; ! [stream catDouble: val]; ! } ! ! - (void)lispSaveStream: stream Integer: (const char*) aName Value: (int)val ! { ! [stream catSeparator]; ! [stream catKeyword: aName ]; ! [stream catSeparator]; ! [stream catDouble: val]; ! } ! ! - (void)bareLispOutDeep: stream ! { ! [self lispSaveStream: stream Double: "demand" Value: demand]; ! [self lispSaveStream: stream Double: "profit" Value: profit]; ! [self lispSaveStream: stream Double: "wealth" Value: wealth]; ! [self lispSaveStream: stream Double: "position" Value: position]; ! [self lispSaveStream: stream Double: "cash" Value: cash]; ! [self lispSaveStream: stream Double: "initialcash" Value: initialcash]; ! [self lispSaveStream: stream Double: "minholding" Value:minholding]; ! [self lispSaveStream: stream Double: "mincash" Value: mincash]; ! [self lispSaveStream: stream Double: "intrate" Value: intrate]; ! [self lispSaveStream: stream Double: "intratep1" Value: intratep1]; ! [self lispSaveStream: stream Double: "price" Value: price]; ! [self lispSaveStream: stream Double: "dividend" Value: dividend]; ! [self lispSaveStream: stream Integer: "myID" Value: myID]; ! ! } ! ! ! ! ! @end ! ! ! ! ! ! ! ! ! ! ! ! ! diff -rc ASM-2.2.1/ASMBatchSwarm.m ASM-2.4/ASMBatchSwarm.m *** ASM-2.2.1/ASMBatchSwarm.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/ASMBatchSwarm.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 11,23 **** +createBegin: (id)aZone { ASMBatchSwarm * obj; ! ! obj = [super createBegin: aZone]; ! ! //overridden by settings from scm file ! // obj->loggingFrequency = 1; ! //obj->experimentDuration = 500; ! return obj; } --- 11,17 ---- +createBegin: (id)aZone { ASMBatchSwarm * obj; ! obj = [super createBegin: aZone]; return obj; } *************** *** 28,70 **** { id modelZone; BFParams * bfParams = [(id)arguments getBFParams]; ASMModelParams * asmModelParams = [(id)arguments getModelParams]; output = [[Output createBegin: self] createEnd]; [super buildObjects]; ! modelZone = [Zone create: [self getZone]]; ! asmModelSwarm = [ASMModelSwarm create: modelZone]; [asmModelSwarm setOutputObject: output]; [asmModelSwarm setParamsModel: asmModelParams BF: bfParams]; - //ObjectLoader: is deprecated - //: [ObjectLoader load: self fromAppDataFileNamed: "batch.setup"]; - - //pj: [ObjectLoader load: asmModelSwarm fromAppDataFileNamed: "param.data"]; - [asmModelSwarm buildObjects]; ! output = [asmModelSwarm getOutput]; ! [output prepareOutputFile]; [output writeParams: asmModelParams BFAgent: bfParams Time: 0]; return self; } /*"Create schedules. Assures that the output object writes the data when needed and checks to see if the required number of time steps has been completed"*/ ! -buildActions ! { [super buildActions]; [asmModelSwarm buildActions]; if(loggingFrequency) { displayActions = [ActionGroup create: [self getZone]]; ! [displayActions createActionTo: output message: M(writeData)]; ! displaySchedule = [Schedule createBegin: [self getZone]]; [displaySchedule setRepeatInterval: loggingFrequency]; displaySchedule = [displaySchedule createEnd]; --- 22,65 ---- { id modelZone; BFParams * bfParams = [(id)arguments getBFParams]; + ASMModelParams * asmModelParams = [(id)arguments getModelParams]; + output = [[Output createBegin: self] createEnd]; [super buildObjects]; ! asmModelSwarm = [ASMModelSwarm create: self]; ! [asmModelSwarm setOutputObject: output]; [asmModelSwarm setParamsModel: asmModelParams BF: bfParams]; [asmModelSwarm buildObjects]; ! [output createTimePlots]; ! [output prepareCOutputFile]; [output writeParams: asmModelParams BFAgent: bfParams Time: 0]; return self; } /*"Create schedules. Assures that the output object writes the data when needed and checks to see if the required number of time steps has been completed"*/ ! - buildActions ! { ! id agentlist; [super buildActions]; [asmModelSwarm buildActions]; if(loggingFrequency) { + agentlist = [asmModelSwarm getAgentList]; + displayActions = [ActionGroup create: [self getZone]]; ! [displayActions createActionTo: output message: M(writeCData)]; ! [displayActions createActionTo: output message: M(stepPlots)]; ! displaySchedule = [Schedule createBegin: [self getZone]]; [displaySchedule setRepeatInterval: loggingFrequency]; displaySchedule = [displaySchedule createEnd]; *************** *** 78,84 **** } /*"activateIn: is required to preserve the hierarchy of schedules across many levels"*/ ! -activateIn: (id)swarmContext { [super activateIn: swarmContext]; [asmModelSwarm activateIn: self]; --- 73,79 ---- } /*"activateIn: is required to preserve the hierarchy of schedules across many levels"*/ ! - activateIn: (id)swarmContext { [super activateIn: swarmContext]; [asmModelSwarm activateIn: self]; *************** *** 117,122 **** --- 112,118 ---- /*"tell the top level swarm to terminate the simulation"*/ -stopRunning { + [asmModelSwarm lispArchive: "end"]; [getTopLevelActivity() terminate]; return self; } diff -rc ASM-2.2.1/ASMModelParams.h ASM-2.4/ASMModelParams.h *** ASM-2.2.1/ASMModelParams.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/ASMModelParams.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 15,21 **** double mindividend; double maxdividend; double amplitude; ! int period; int exponentialMAs; //Also used by World.//pj:was BOOL //Specialist parameters double maxprice; --- 15,21 ---- double mindividend; double maxdividend; double amplitude; ! double period; int exponentialMAs; //Also used by World.//pj:was BOOL //Specialist parameters double maxprice; *************** *** 32,41 **** int randomSeed; //Agent parameters overridden by the BFagent. //These might be used for other agents that a user implements. - double tauv; - double lambda; double maxbid; - double initvar; double maxdev; int setOutputForData; }; --- 32,38 ---- diff -rc ASM-2.2.1/ASMModelParams.m ASM-2.4/ASMModelParams.m *** ASM-2.2.1/ASMModelParams.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/ASMModelParams.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 79,92 **** inClass: [self class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "randomSeed" inClass: [self class]]]; - [probeMap addProbe: [probeLibrary getProbeForVariable: "tauv" - inClass: [self class]]]; - [probeMap addProbe: [probeLibrary getProbeForVariable: "lambda" - inClass: [self class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "maxbid" inClass: [self class]]]; - [probeMap addProbe: [probeLibrary getProbeForVariable: "initvar" - inClass: [self class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "maxdev" inClass: [self class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "setOutputForData" --- 79,86 ---- diff -rc ASM-2.2.1/ASMModelSwarm.h ASM-2.4/ASMModelSwarm.h *** ASM-2.2.1/ASMModelSwarm.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/ASMModelSwarm.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 6,12 **** #import "Output.h" #import "ASMModelParams.h" - @interface ASMModelSwarm: Swarm { int modelTime; /*"An integer used to represent the current timestep"*/ --- 6,11 ---- *************** *** 42,49 **** --- 41,62 ---- - setBatchRandomSeed: (int)newSeed; - buildObjects; + + - createAgents; + + + - lispArchive: (char *)inputName; + - lispLoadAgents: (const char *)lispfile; + - lispLoadWorld: (const char *)lispfile; + - writeParams; - buildActions; + + - (void)updateAgentPerformance; + - (void)prepareAgentsForTrading; + - (void)creditAgentEarningsAndPayTaxes; + + - activateIn: (id)swarmContext; - doWarmupStep; *************** *** 55,60 **** --- 68,74 ---- -(void) drop; + @end diff -rc ASM-2.2.1/ASMModelSwarm.m ASM-2.4/ASMModelSwarm.m *** ASM-2.2.1/ASMModelSwarm.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/ASMModelSwarm.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 2,10 **** #import #import "Output.h" #import "BFParams.h" ! #import "BFCast.h" #import #include --- 2,12 ---- #import #import "Output.h" #import "BFParams.h" ! #import "Parameters.h" ! #import "BFagent.h" #import + #include *************** *** 77,83 **** { bfParams = bfp; asmModelParams=modelParams; ! fprintf(stderr,"Param object %d ",asmModelParams->numBFagents); return self; } --- 79,85 ---- { bfParams = bfp; asmModelParams=modelParams; ! fprintf(stderr,"Param object %d \n\n",asmModelParams->numBFagents); return self; } *************** *** 150,162 **** /*"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) */ --- 152,165 ---- /*"Build and initialize objects"*/ - buildObjects { if(asmModelParams->randomSeed != 0) [randomGenerator setStateFromSeed: asmModelParams->randomSeed]; ! else ! asmModelParams->randomSeed = [randomGenerator getInitialSeed]; ! ! //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) */ *************** *** 170,180 **** [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]; --- 173,190 ---- [dividendProcess setDerivedParams]; dividendProcess = [dividendProcess createEnd]; ! if (![(Parameters *)arguments getFilename]) ! { ! world = [World createBegin: [self getZone]]; ! [world setintrate: asmModelParams->intrate]; ! [world setExponentialMAs: asmModelParams->exponentialMAs]; ! [world initWithBaseline:asmModelParams-> baseline]; ! world = [world createEnd]; ! } ! else ! { ! [self lispLoadWorld: [(Parameters *)arguments getFilename]]; ! } specialist = [Specialist createBegin: [self getZone]]; [specialist setMaxPrice: asmModelParams->maxprice]; *************** *** 188,206 **** [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; --- 198,238 ---- [specialist setREB: asmModelParams->reb]; specialist = [specialist createEnd]; + + [output setWorld: world]; [output setSpecialist: specialist]; ! /* Set class variables */ [BFagent init]; [BFagent setBFParameterObject: bfParams]; [BFagent setWorld: world]; ! ! ! if (![(Parameters *)arguments getFilename]) ! { ! ! /* Initialize the agent modules and create the agents */ ! agentList = [List create: [self getZone]]; //create list for agents ! ! [self createAgents]; ! } ! ! else ! { ! [self lispLoadAgents: [(Parameters *)arguments getFilename]]; ! } ! ! [output setAgentlist: agentList]; ! return self; ! } ! ! /*"Create agents, when they are not loaded in serialized form"*/ ! - createAgents ! { ! int i; ! for (i = 0; i < asmModelParams->numBFagents; i++) { BFagent * agent; *************** *** 212,224 **** --- 244,320 ---- [agent setInitialHoldings]; [agent setPosition: asmModelParams->initholding]; [agent initForecasts]; + [agent setAgentList: agentList]; agent = [agent createEnd]; [agentList addLast: agent]; } + return self; + } + + + + + - lispArchive: (char *)inputName + { + char dataArchiveName[100]; + if (!inputName) + snprintf(dataArchiveName,100,"%s%d-%s.scm","run",getInt(arguments,"run"),"blah"); + else + snprintf(dataArchiveName,100,"%s%d-%s.scm","run",getInt(arguments,"run"),inputName); + id dataArchiver = [LispArchiver create: [self getZone] setPath: dataArchiveName]; + + [dataArchiver putShallow: "asmModelParams" object: asmModelParams]; + [dataArchiver putShallow: "bfParams" object: bfParams]; + [dataArchiver putDeep: "world" object: world]; + [dataArchiver putDeep: "agentList" object: agentList]; + + // [dataArchiver putShallow: "parameters" object: parameters]; + + [dataArchiver sync]; + [dataArchiver drop]; + + return self; + } + + + + + - lispLoadAgents: (const char *)lispfile + { + id index; + id anAgent; + id archiver = [LispArchiver create: [self getZone] setPath: lispfile]; + agentList = [archiver getObject: "agentList"]; + + [archiver drop]; + + index = [agentList begin: self]; + for (anAgent=[index next]; [index getLoc]==Member; anAgent= [index next]) + { + [anAgent setAgentList: agentList]; + printf ("ID IS %d", [anAgent getID]); + } return self; } + + - lispLoadWorld: (const char *)lispfile + { + id archiver = [LispArchiver create: [self getZone] setPath: lispfile]; + world = [archiver getObject: "world"]; + + [archiver drop]; + + return self; + } + + + + + + + /*"This triggers a writing of the model parameters, for record keeping."*/ - writeParams { *************** *** 237,308 **** { [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]; --- 333,436 ---- { [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 createActionTo: self ! message: M(creditAgentEarningsAndPayTaxes)]; ! [periodActions createActionTo: world message: M(updateWorld)]; ! // Tell BFagents to get ready for trading (they may run GAs here) ! [periodActions createActionTo: self ! message: M(prepareAgentsForTrading)]; ! // 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]; ! ! // Another way to tell agents to update their performance, equally fast ! [periodActions createActionTo: self ! message: M(updateAgentPerformance)]; ! ! ! startupSchedule = [Schedule create: [self getZone] setAutoDrop: YES]; ! ! ! if (![(Parameters *)arguments getFilename]) ! { ! //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 < 501; i++) ! [startupSchedule at: 0 createActionTo: self message:M(doWarmupStep)]; ! } ! } ! ! periodSchedule = [Schedule createBegin: [self getZone]]; ! [periodSchedule setRepeatInterval: 1]; ! periodSchedule = [periodSchedule createEnd]; ! [periodSchedule at: 0 createAction: periodActions]; ! ! return self; ! } ! - (void)updateAgentPerformance ! { ! id index = [agentList begin: self]; ! id anAgent; ! for (anAgent = [index next]; [index getLoc]==Member; anAgent= [index next]) ! { ! [anAgent updatePerformance]; ! } ! [index drop]; ! } ! - (void)prepareAgentsForTrading ! { ! id index = [agentList begin: self]; ! id anAgent; ! for (anAgent = [index next]; [index getLoc]==Member; anAgent= [index next]) ! { ! [anAgent prepareForTrading]; ! } ! [index drop]; ! } ! - (void)creditAgentEarningsAndPayTaxes ! { ! id index = [agentList begin: self]; ! id anAgent; ! for (anAgent = [index next]; [index getLoc]==Member; anAgent= [index next]) ! { ! [anAgent creditEarningsAndPayTaxes ]; ! } ! [index drop]; } + /*"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]; *************** *** 349,354 **** --- 477,485 ---- [super drop]; } + + + @end diff -rc ASM-2.2.1/ASMObserverSwarm.h ASM-2.4/ASMObserverSwarm.h *** ASM-2.2.1/ASMObserverSwarm.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/ASMObserverSwarm.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 20,30 **** BOOL writeParams; /*"Indicator that files including parameter values should be written"*/ BOOL writeData;/*"Indicator that files including output values should be written"*/ - id priceGraph; /*"Time plot of risk neutral and observed market price"*/ - - id volumeGraph; /*"Time plot of market trading volume"*/ - - id positionHisto;/*"Histogram showing amount of stock held by each individual agent"*/ //Histo *cashHisto; //A histogram for agent cash holdings. id relativeWealthHisto;/*"Histogram showing wealth of agents"*/ --- 20,25 ---- *************** *** 49,59 **** #endif - createEnd; - _writeRawData_; ! - buildObjects; ! - priceGraphDeath_ : caller; ! - volumeGraphDeath_ : caller; - updateHistos; - writeSimulationParams; - (BOOL)ifParamWrite; --- 44,57 ---- #endif - createEnd; - _writeRawData_; ! - lispSaveSerial: (char *)inputName; - buildObjects; ! ! - _positionHistoDeath_ : caller; ! - _relativeWealthHistoDeath_ : caller; ! ! - updateHistos; - writeSimulationParams; - (BOOL)ifParamWrite; diff -rc ASM-2.2.1/ASMObserverSwarm.m ASM-2.4/ASMObserverSwarm.m *** ASM-2.2.1/ASMObserverSwarm.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/ASMObserverSwarm.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 4,10 **** #include ! @implementation ASMObserverSwarm /*" The ASMObserverSwarm is a Swarm with a graphical user interface --- 4,10 ---- #include ! @implementation ASMObserverSwarm /*" The ASMObserverSwarm is a Swarm with a graphical user interface *************** *** 31,37 **** id probeMap; obj = [super createBegin: aZone]; ! obj->displayFrequency = 3; probeMap = [EmptyProbeMap createBegin: aZone]; [probeMap setProbedClass: [self class]]; --- 31,37 ---- id probeMap; obj = [super createBegin: aZone]; ! obj->displayFrequency = 100; probeMap = [EmptyProbeMap createBegin: aZone]; [probeMap setProbedClass: [self class]]; *************** *** 44,49 **** --- 44,52 ---- [probeMap addProbe: [probeLibrary getProbeForMessage: "toggleDataWrite" inClass: [self class]]]; + [probeMap addProbe: [probeLibrary getProbeForMessage: "lispSaveSerial:" + inClass: [self class]]]; + //The member functions that allow you to print a graph. #if 0 [probeMap addProbe: [probeLibrary getProbeForMessage: *************** *** 118,165 **** //need to create output and parameters so they exist from beginning ASMModelParams * asmModelParams = [(id)arguments getModelParams]; BFParams * bfParams = [(id)arguments getBFParams]; - output = [[Output createBegin: self] createEnd]; [super buildObjects]; asmModelSwarm = [ASMModelSwarm create: self]; [asmModelSwarm setOutputObject: output]; CREATE_ARCHIVED_PROBE_DISPLAY (self); CREATE_ARCHIVED_PROBE_DISPLAY (asmModelParams); CREATE_ARCHIVED_PROBE_DISPLAY (bfParams); [controlPanel setStateStopped]; // Don't set the parameter objects until the model starts up That // way, any changes typed into the gui will be taken into account by // the model. [asmModelSwarm setParamsModel: asmModelParams BF: bfParams]; - [asmModelSwarm buildObjects]; ! numagents = asmModelParams->numBFagents; ! priceGraph = [EZGraph create: self setTitle: "Price v. time" ! setAxisLabelsX: "time" Y: "price" ! setWindowGeometryRecordName: "priceGraph"]; ! [priceGraph enableDestroyNotification: self ! notificationMethod: @selector (_priceGraphDeath_:)]; ! [priceGraph createSequence: "actual price" ! withFeedFrom: [asmModelSwarm getWorld] ! andSelector: M(getPrice)]; ! [priceGraph createSequence: "risk neutral price" ! withFeedFrom: [asmModelSwarm getWorld] ! andSelector: M(getRiskNeutral)]; ! ! volumeGraph = [EZGraph create: self setTitle: "Volume v. time" ! setAxisLabelsX: "time" Y: "volume" ! setWindowGeometryRecordName: "volumeGraph"]; ! ! [volumeGraph createSequence: "actual price" ! withFeedFrom: [asmModelSwarm getSpecialist] ! andSelector: M(getVolume)]; ! ! [priceGraph enableDestroyNotification: self ! notificationMethod: @selector (_volumeGraphDeath_:)]; positionHisto = [Histogram createBegin: [self getZone]]; SET_WINDOW_GEOMETRY_RECORD_NAME (positionHisto); --- 121,153 ---- //need to create output and parameters so they exist from beginning ASMModelParams * asmModelParams = [(id)arguments getModelParams]; BFParams * bfParams = [(id)arguments getBFParams]; [super buildObjects]; + + output = [[Output createBegin: self] createEnd]; + asmModelSwarm = [ASMModelSwarm create: self]; + [asmModelSwarm setOutputObject: output]; CREATE_ARCHIVED_PROBE_DISPLAY (self); CREATE_ARCHIVED_PROBE_DISPLAY (asmModelParams); CREATE_ARCHIVED_PROBE_DISPLAY (bfParams); [controlPanel setStateStopped]; + + if ([controlPanel getState] == ControlStateQuit) + return self; // Don't set the parameter objects until the model starts up That // way, any changes typed into the gui will be taken into account by // the model. [asmModelSwarm setParamsModel: asmModelParams BF: bfParams]; ! [asmModelSwarm buildObjects]; ! [output createTimePlots]; ! numagents = asmModelParams->numBFagents; positionHisto = [Histogram createBegin: [self getZone]]; SET_WINDOW_GEOMETRY_RECORD_NAME (positionHisto); *************** *** 172,177 **** --- 160,169 ---- [positionHisto setAxisLabelsX: "agents" Y: "position"]; [positionHisto pack]; + [positionHisto enableDestroyNotification: self + notificationMethod: @selector (_positionHistoDeath_:)]; + + //Again, you can add this back. //cashHisto = [Histo create: [self getZone]]; //[cashHisto setWidth: 500 Height: 250]; *************** *** 192,243 **** [relativeWealthHisto setTitle: "Relative Wealth of Agents"]; [relativeWealthHisto setAxisLabelsX: "agents" Y: "relative wealth"]; [relativeWealthHisto pack]; - - //Only interesting to compare multiple agents. - //deviationGraph = [Graph createBegin: [self getZone]]; - //SET_WINDOW_GEOMETRY_RECORD_NAME (deviationGraph); - //deviationGraph = [deviationGraph createEnd]; - - //[deviationGraph setTitle: "Mean Abs Dev of Different Agents"]; - //[deviationGraph setAxisLabelsX: "time" Y: "mean abs dev/actual p+d"]; - //[deviationGraph setRangesYMin: 0.0 Max: 200.0]; - //[deviationGraph pack]; - ! //deviationData = [deviationGraph createElement]; ! //[[deviationData setLabel: "BF"] setColor: "green"]; ! ! //deviationAverager = [Averager createBegin: [self getZone]]; ! //[deviationAverager setCollection: [asmModelSwarm getAgentList]]; ! //[deviationAverager setProbedSelector: M(getDeviation)]; ! //deviationAverager = [deviationAverager createEnd]; ! ! //deviationGrapher = [ActiveGraph createBegin: [self getZone]]; ! //[deviationGrapher setElement: deviationData]; ! //[deviationGrapher setDataFeed: deviationAverager]; ! //[deviationGrapher setProbedSelector: M(getAverage)]; ! //deviationGrapher = [deviationGrapher createEnd]; ! return self; } ! /*"This method is needed to stop run-time hangs when users close graph windows by clicking on their system's window close button"*/ ! - priceGraphDeath_ : caller { ! [priceGraph drop]; ! priceGraph = nil; return self; } ! /*"This method is needed to stop run-time hangs when users close graph windows by clicking on their system's window close button"*/ ! - volumeGraphDeath_ : caller { ! [volumeGraph drop]; ! volumeGraph = nil; return self; } /*" This method gathers data about the agents, puts it into arrays, and then passes those arrays to the histogram objects. As soon as we tell the histograms to draw themselves, we will see the result"*/ --- 184,214 ---- [relativeWealthHisto setTitle: "Relative Wealth of Agents"]; [relativeWealthHisto setAxisLabelsX: "agents" Y: "relative wealth"]; [relativeWealthHisto pack]; ! [relativeWealthHisto enableDestroyNotification: self ! notificationMethod: @selector (_relativeWealthHistoDeath_:)]; ! return self; } ! - _positionHistoDeath_ : caller { ! [positionHisto drop]; ! positionHisto = nil; return self; } ! ! ! - _relativeWealthHistoDeath_ : caller { ! [relativeWealthHisto drop]; ! relativeWealthHisto = nil; return self; } + /*" This method gathers data about the agents, puts it into arrays, and then passes those arrays to the histogram objects. As soon as we tell the histograms to draw themselves, we will see the result"*/ *************** *** 258,264 **** double initcash=[(id)arguments getModelParams]->initialcash; position[i] = [agent getAgentPosition]; relativeWealth[i] = [agent getWealth]/initcash; - //cash[i] = [agent getCash]; } [index drop]; [positionHisto drawHistogramWithDouble: position]; --- 229,234 ---- *************** *** 300,309 **** /*"This toggles data writing features. It can be accessed by punching a button in a probe display that is shown on the screen when the simulation begins"*/ ! -(BOOL)toggleDataWrite { if(writeData != YES) { ! [output prepareOutputFile]; writeData = YES; } else writeData = NO; --- 270,280 ---- /*"This toggles data writing features. It can be accessed by punching a button in a probe display that is shown on the screen when the simulation begins"*/ ! -(BOOL)toggleDataWrite ! { if(writeData != YES) { ! [output prepareCOutputFile]; writeData = YES; } else writeData = NO; *************** *** 315,326 **** /*"If data logging is turned on, this cause data to be written whenever it is called"*/ - _writeRawData_ { if (writeData == YES) ! [output writeData]; return self; } /*" Create actions and schedules onto which the actions are put. Since this is an observer, the actions are intended to make sure data is collected, displayed to the screen, and written to files --- 286,311 ---- /*"If data logging is turned on, this cause data to be written whenever it is called"*/ - _writeRawData_ { + id agentlist; //BaT 10.09.2002 + agentlist = [asmModelSwarm getAgentList];//BaT 10.09.2002 if (writeData == YES) ! [output writeCData]; //BaT 10.09.2002 ! return self; ! } ! ! ! - lispSaveSerial: (char *)inputName ! { ! ! char dataArchiveName[100]; ! ! snprintf(dataArchiveName,100,"%s-%ld",inputName,[asmModelSwarm getModelTime]); ! [asmModelSwarm lispArchive: dataArchiveName]; return self; } + /*" Create actions and schedules onto which the actions are put. Since this is an observer, the actions are intended to make sure data is collected, displayed to the screen, and written to files *************** *** 333,348 **** displayActions = [ActionGroup create: [self getZone]]; ! [displayActions createActionTo: self ! message: M(_writeRawData_)]; ! [displayActions createActionTo: self message: M(updateHistos)]; ! [displayActions createActionTo: priceGraph message: M(step)]; ! // [displayActions createActionTo: riskNeutralGrapher message: M(step)]; ! [displayActions createActionTo: volumeGraph message: M(step)]; ! //[displayActions createActionTo: deviationAverager message: M(update)]; ! //[displayActions createActionTo: deviationGrapher message: M(step)]; [displayActions createActionTo: probeDisplayManager message: M(update)]; [displayActions createActionTo: actionCache message: M(doTkEvents)]; displaySchedule = [Schedule createBegin: [self getZone]]; --- 318,332 ---- displayActions = [ActionGroup create: [self getZone]]; ! [displayActions createActionTo: self message: M(updateHistos)]; ! ! [displayActions createActionTo: output message: M(stepPlots)]; ! ! [displayActions createActionTo: self message: M(_writeRawData_)]; ! [displayActions createActionTo: probeDisplayManager message: M(update)]; + [displayActions createActionTo: actionCache message: M(doTkEvents)]; displaySchedule = [Schedule createBegin: [self getZone]]; *************** *** 355,367 **** /*"This method activates the model swarm within the context of this ! observer, and then it activated the observer's schedules. This makes sure that the actions inserted at time t inside the model are placed into the overall time sequence before the observer scheduled actions that update graphs which describe the results"*/ - activateIn: swarmContext { [super activateIn: swarmContext]; [asmModelSwarm activateIn: self]; [displaySchedule activateIn: self]; --- 339,352 ---- /*"This method activates the model swarm within the context of this ! observer, and then it activates the observer's schedule. This makes sure that the actions inserted at time t inside the model are placed into the overall time sequence before the observer scheduled actions that update graphs which describe the results"*/ - activateIn: swarmContext { [super activateIn: swarmContext]; + [asmModelSwarm activateIn: self]; [displaySchedule activateIn: self]; *************** *** 378,383 **** --- 363,371 ---- -(void) drop { [self expostParamWrite]; + + [positionHisto drop]; + [relativeWealthHisto drop]; [asmModelSwarm drop]; [super drop]; } diff -rc ASM-2.2.1/asm.scm ASM-2.4/asm.scm *** ASM-2.2.1/asm.scm 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/asm.scm 2003-06-21 12:33:21.000000000 -0500 *************** *** 2,82 **** (cons 'bfParams (make-instance 'BFParams ! #:numfcasts 60 ! #:tauv 50.0D0 ! #:lambda 0.3D0 #:maxbid 10.0D0 ! #:mincount 5 ! #:subrange 0.5D0 ! #:gafrequency 100 #:firstgatime 100 ! #:longtime 2000 ! #:individual 0 ! #:a_min 0.0D0 ! #:a_max 1.98D0 #:b_min 0D0 #:b_max 0D0 #:c_min -10D0 ! #:c_max 11.799979D0 ! #:newfcastvar 4.000212D0 ! #:initvar 4.000212D0 ! #:bitcost 0.01D0 ! #:maxdev 100D0 #:bitprob 0.1D0 ! #:poolfrac 0.1D0 ! #:newfrac 0.05D0 ! #:pcrossover 0.3D0 #:plinear 0.333D0 #:prandom 0.333D0 ! #:pmutation 0.01D0 ! #:plong 0.05D0 #:pshort 0.2D0 #:nhood 0.05D0 ! #:genfrac 0.10D0 ! #:nnulls 0 ! #:condbits 16 #:npoolmax -1 #:nnewmax -1 #:ncondmax -1 )) (cons 'asmModelParams (make-instance 'ASMModelParams ! #:numBFagents 30 #:initholding 1D0 ! #:initialcash 10000D0 ! #:minholding 0D0 ! #:mincash 0D0 #:intrate 0.1D0 #:baseline 10D0 #:mindividend 0.00005D0 #:maxdividend 100D0 ! #:amplitude 0.14178D0 ! #:period 1.0D0 ! #:maxprice 500D0 #:minprice 0.001D0 #:taup 50.0D0 ! #:sptype 2 ! #:maxiterations 10 #:minexcess 0.01D0 #:eta 0.0005D0 #:etamax 0.05D0 #:etamin 0.00001D0 ! #:rea 9.0D0 ! #:reb 2.0D0 ! #:randomSeed 0 ! #:tauv 50.0D0 ! #:lambda 0.3D0 #:maxbid 10.0D0 ! #:initvar 0.4000212D0 ! #:maxdev 100D0 #:exponentialMAs 1 )) (cons 'asmBatchSwarm (make-instance 'ASMBatchSwarm ! #:loggingFrequency 3 ! #:experimentDuration 500 ! )) ) --- 2,81 ---- (cons 'bfParams (make-instance 'BFParams ! #:numfcasts 100 ! #:tauv 75.0D0 ! #:lambda 0.5D0 #:maxbid 10.0D0 ! #:mincount 2 ! #:subrange 1 ! #:gafrequency 1000 #:firstgatime 100 ! #:longtime 4000 ! #:individual 1 ! #:a_min 0.7D0 ! #:a_max 1.2D0 #:b_min 0D0 #:b_max 0D0 #:c_min -10D0 ! #:c_max 19.002D0 ! #:newfcastvar 4.0D0 ! #:initvar 4.0D0 ! #:bitcost 0.005D0 ! #:maxdev 500D0 #:bitprob 0.1D0 ! #:poolfrac 0.2D0 ! #:newfrac 0.2D0 ! #:pcrossover 0.1D0 ! #:psocial 0.0D0 ! #:startsocial 100000 #:plinear 0.333D0 #:prandom 0.333D0 ! #:pmutation 0.03D0 ! #:plong 0.2D0 #:pshort 0.2D0 #:nhood 0.05D0 ! #:genfrac 0.25D0 ! #:nnulls 4 ! #:condbits 12 #:npoolmax -1 #:nnewmax -1 #:ncondmax -1 )) (cons 'asmModelParams (make-instance 'ASMModelParams ! #:numBFagents 25 #:initholding 1D0 ! #:initialcash 20000D0 ! #:minholding -5D0 ! #:mincash -2000D0 #:intrate 0.1D0 #:baseline 10D0 #:mindividend 0.00005D0 #:maxdividend 100D0 ! #:amplitude 0.0873D0 ! #:period 19.5D0 ! #:maxprice 99999D0 #:minprice 0.001D0 #:taup 50.0D0 ! #:sptype 1 ! #:maxiterations 20 #:minexcess 0.01D0 #:eta 0.0005D0 #:etamax 0.05D0 #:etamin 0.00001D0 ! #:rea 6.333D0 ! #:reb 16.6882D0 ! #:randomSeed 0 #:maxbid 10.0D0 ! #:maxdev 500D0 #:exponentialMAs 1 )) (cons 'asmBatchSwarm (make-instance 'ASMBatchSwarm ! #:loggingFrequency 1000 ! #:experimentDuration 350000 ! )) ) Only in ASM-2.2.1: batch.setup diff -rc ASM-2.2.1/BFagent.h ASM-2.4/BFagent.h *** ASM-2.2.1/BFagent.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/BFagent.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 7,47 **** #import "World.h" - //pj: // Structure for list of individual forecasts - //pj: struct BF_fcast - //pj: THIS STRUCT HAS MOVED INTO ITS OWN CLASS, BFCast. Go see. - - //pj: struct BFparams moved to its own class, BFParams. - //pj: I did not rename for fun, but to help make sure all code was completely updated. - @interface BFagent:Agent { 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; /*"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; /*"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?"*/ ! // int nactive; BFParams * privateParams; /*"BFParams object holds parameters of this object"*/ id fcastList; /*"A Swarm Array, holding the forecasts that the agent might use"*/ id activeList; /*"A Swarm list containing a subset of all forecasts"*/ id oldActiveList; /*"A copy of the activeList from the previous time step"*/ } + (void)setBFParameterObject: x; + (void)init; - createEnd; - initForecasts; - (BFCast *)createNewForecast; //all conditions=0 --- 7,43 ---- #import "World.h" @interface BFagent:Agent { int currentTime; /*"The agent regularly checks with Swarm to see what time it is"*/ double forecast; /*"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; /*"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 medianstrength; + 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?"*/ ! BFParams * privateParams; /*"BFParams object holds parameters of this object"*/ id fcastList; /*"A Swarm Array, holding the forecasts that the agent might use"*/ id activeList; /*"A Swarm list containing a subset of all forecasts"*/ id oldActiveList; /*"A copy of the activeList from the previous time step"*/ + BFCast * strongestBFCast; /*"A pointer to the strongest rule of the agent"*/ } + (void)setBFParameterObject: x; + (void)init; + - (BFCast *)getStrongestBFCast; - createEnd; - initForecasts; + - (int)getNfcasts; - (BFCast *)createNewForecast; //all conditions=0 *************** *** 50,67 **** - (BitVector *) collectWorldData: aZone; - updateActiveList: (BitVector *)worldvalues; - - getInputValues; //does nothing, used only if their are ANNagents - - feedForward; //does nothing, used only if their are ANNagents - (double)getDemandAndSlope: (double *)slope forPrice: (double)trialprice; - (double)getRealForecast; - updatePerformance; - (double)getDeviation; - - updateWeights; //does nothing, used only if their are ANNagents - (int)nbits; - (int)nrules; - performGA; ! - (int)lastgatime; - printcond: (int)word; --- 46,73 ---- - (BitVector *) collectWorldData: aZone; - updateActiveList: (BitVector *)worldvalues; - (double)getDemandAndSlope: (double *)slope forPrice: (double)trialprice; - (double)getRealForecast; + - (double)getMedianstrength; - updatePerformance; - (double)getDeviation; - (int)nbits; - (int)nrules; - performGA; ! ! - (BFCast *) CopyRule:(BFCast *) to From: (BFCast *) from; ! - (void) MakePool: (id )rejects From: (id ) list; ! - (BOOL) Mutate: (BFCast *) new Status: (BOOL) changed Strength: (double)medstrength; ! - (BFCast *) Crossover:(BFCast *) newForecast Parent1: (BFCast *) parent1 Parent2: (BFCast *) parent2 Strength: (double)medstrength; ! - (void) TransferFcastsFrom: newList To: forecastList Replace: rejects; ! - (BFCast *) GetMort: (BFCast *) new Rejects: (id ) rejects; ! - (void) Generalize: (id) list Strength: (double) strength; ! - (BFCast *) Tournament: (id ) list; ! - (double) CalculateAndUseMadv; ! - (double) CalculateMedian; ! - (BFCast *) FcastSetParams: (BFCast *)aNewForecast Strength: (double)medstrength Madv: (double)madv; ! - (BOOL) PickParents: (BFCast *) aNewForecast Strength: (double)medstrength; - printcond: (int)word; *************** *** 71,76 **** --- 77,85 ---- - (int)fMoments: (double *)moment cumulative: (BOOL)cum; - (const char *)descriptionOfBit:(int)bit; + - (void)lispOutDeep: stream; + - (void)bareLispOutDeep: stream; + @end diff -rc ASM-2.2.1/BFagent.m ASM-2.4/BFagent.m *** ASM-2.2.1/BFagent.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/BFagent.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 105,149 **** Iteration now uses Swarm index objects. Many usages of C alloc and calloc are eliminated. This should approach a high level of readability. - Example: code that used to look like this for looping through a list: - struct BF_fcast *fptr, *topfptr; - topfptr = fcast + p->numfcasts; - for (fptr = fcast; fptr < topfptr; fptr++) - { - if (fptr->conditions[0] & real0) continue; - *nextptr = fptr; - nextptr = &fptr->next; - } - - Now it looks like this: - id index=[ fcastList begin: [self getZone]]; - for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) - { - if ( [aForecast getConditionsWord: 0] & real0 ) continue ; - //if that's true, this does not get done: - [activeList addLast: aForecast]; - } - [index drop]; - - Example 2: What 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]++; - } - Is now like this: - 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]; - Note the usage of Swarm lists, indexes, and methods like "getConditionsbit" and "getConditionsWord", instead of bitmath. --- 105,110 ---- *************** *** 187,193 **** extern World *worldForAgent; //pj: wish I could get rid of that one too, since each agent could ! //just have a pointer pj: to a common world object. However, there are //serveral class methods that use it. //pj: --- 148,154 ---- extern World *worldForAgent; //pj: wish I could get rid of that one too, since each agent could ! //just have a pointer to a common world object. However, there are //serveral class methods that use it. //pj: *************** *** 197,208 **** #define urand() [uniformDblRand getDoubleWithMin: -1 withMax: 1] #define irand(x) [uniformIntRand getIntegerWithMin: 0 withMax: x-1] - // Type of forecasting. WEIGHTED forecasting is untested in its - // present form. - //pj: bluntly, WEIGHTED does not work and is incomplete, It never worked - // in ASM-2.0, and that's why it is commented out by setting WEIGHTED to 0. - #define WEIGHTED 0 - //pj: this is a static global declaration of the params object, shared by all instances. //pj: note there is also a local copy which is, in current code, intitially the same thing, //pj: and it never changes. The original code had 3 of these, so I'm slimmer by 1/3. --- 158,163 ---- *************** *** 213,233 **** //pj: ReadBitname moved to BFParams - //pj: This is the only global variable I still need, and I'm looking for a way go get rid of it! - static double minstrength; // PRIVATE METHODS @interface BFagent(Private) ! //pj: methods now replace previous functions: ! - (BFCast *) CopyRule:(BFCast *) to From: (BFCast *) from; ! - (void) MakePool: (id )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; ! - (BFCast *) Tournament: (id ) list; @end --- 168,178 ---- //pj: ReadBitname moved to BFParams // PRIVATE METHODS @interface BFagent(Private) ! @end *************** *** 289,294 **** --- 234,246 ---- return; } + /*"This hands over the stronest forecast of an agent upon request."*/ + - (BFCast *)getStrongestBFCast + { + return strongestBFCast; + } + + /*"This creates the container objects activeList and oldActiveList. In addition, it makes sure that any initialization in the createEnd of the super class is done."*/ *************** *** 309,341 **** would be allowed for in the ASM-2.0."*/ - initForecasts { - int sumspecificity = 0; int i; - BFCast * aForecast; int numfcasts; ! id index; ! // 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 = getInt(privateParams,"numfcasts"); fcastList=[Array create: [self getZone] setCount: numfcasts]; - - avspecificity = 0.0; gacount = 0; ! variance = getDouble(privateParams, "initvar"); [self getPriceFromWorld]; [self getDividendFromWorld]; global_mean = price + dividend; --- 261,284 ---- would be allowed for in the ASM-2.0."*/ - initForecasts { int i; int numfcasts; ! // Initialize our instance variables ! // All instances of BFagent have a copy of the same BFParams object ! // that each agent can 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]; gacount = 0; + medianstrength = 0; ! variance = privateParams->initvar; [self getPriceFromWorld]; [self getDividendFromWorld]; global_mean = price + dividend; *************** *** 345,374 **** // Initialize the forecasts, put them into Swarm Array //keep the 0'th forecast in a "know nothing" condition ! [fcastList atOffset: 0 put: [self createNewForecast]]; ! //create rest of forecasts with random conditions for ( i = 1; i < numfcasts; i++) { id aForecast =[self createNewForecast] ; [self setConditionsRandomly: aForecast]; [fcastList atOffset: i put: aForecast]; //put aForecast into Swarm array "fcastlist" - } - - /* Compute average specificity */ - - //pj: Here is the proper way to iterate over Swarm collections - index=[ fcastList begin: [self getZone] ]; - for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) - { - sumspecificity += [aForecast getSpecificity]; - //[aForecast print]; } ! avspecificity = (double) sumspecificity/(double)numfcasts; ! [index drop]; return self; } /*"Creates a new forecast object (instance of BFCast), with all condition bits set to 00 here, meaning "don't care. It also sets values for the other coefficients inside the BFCast. This method is --- 288,321 ---- // Initialize the forecasts, put them into Swarm Array //keep the 0'th forecast in a "know nothing" condition ! [fcastList atOffset: 0 put: [self createNewForecast]]; ! //create rest of forecasts with random conditions for ( i = 1; i < numfcasts; i++) { id aForecast =[self createNewForecast] ; [self setConditionsRandomly: aForecast]; [fcastList atOffset: i put: aForecast]; //put aForecast into Swarm array "fcastlist" } ! ! return self; } + + /*"Get the number of forecasts that this agent is using"*/ + - (int)getNfcasts + { + return [fcastList getCount]; + } + + /*"Get the median strength of the forecasts of the agent"*/ + - (double) getMedianstrength + { + return medianstrength; + } + + /*"Creates a new forecast object (instance of BFCast), with all condition bits set to 00 here, meaning "don't care. It also sets values for the other coefficients inside the BFCast. This method is *************** *** 377,383 **** - (BFCast *)createNewForecast { BFCast * aForecast; ! //needed to set values of a,b,and c double abase = privateParams->a_min + 0.5*(1.0-privateParams->subrange)*privateParams->a_range; double bbase = privateParams->b_min + 0.5*(1.0-privateParams->subrange)*privateParams->b_range; double cbase = privateParams->c_min + 0.5*(1.0-privateParams->subrange)*privateParams->c_range; --- 324,330 ---- - (BFCast *)createNewForecast { BFCast * aForecast; ! //needed to set values of a,b,and c double abase = privateParams->a_min + 0.5*(1.0-privateParams->subrange)*privateParams->a_range; double bbase = privateParams->b_min + 0.5*(1.0-privateParams->subrange)*privateParams->b_range; double cbase = privateParams->c_min + 0.5*(1.0-privateParams->subrange)*privateParams->c_range; *************** *** 391,415 **** [aForecast setNNulls: privateParams->nnulls]; [aForecast setBitcost: privateParams->bitcost]; aForecast = [aForecast createEnd]; [aForecast setForecast: 0.0]; [aForecast setLforecast: global_mean]; ! //note aForecast has the forecast conditions=0 by its own createEnd. ! //also inside its createEnd, lastactive =1, specificity=0, variance=99999; ! ! //pj: Controversy/confusion BFagent.m as originally distributed used ! //definitions for variance and strength that did not match the ! //bfagent.m file or the documentation. I'm following bfagent.m and ! //the docs, ignoring what was in BFagent.m ! [aForecast setVariance: privateParams->newfcastvar]; //same as bfagent's init [aForecast setStrength: 0.0]; ! /* Set the forecasting parameters for each fcast to random values in a * fraction "subrange" of their range, centered at the midpoint. For * subrange=1 this is the whole range (min to max). For subrange=0.5, * values lie between 1/4 and 3/4 of this range. subrange=0 gives * homogeneous agents, with values at the middle of their min-max range. */ [aForecast setAval : abase + drand()*asubrange]; [aForecast setBval : bbase + drand()*bsubrange]; [aForecast setCval : cbase + drand()*csubrange]; --- 338,360 ---- [aForecast setNNulls: privateParams->nnulls]; [aForecast setBitcost: privateParams->bitcost]; aForecast = [aForecast createEnd]; + [aForecast init]; + + [aForecast setActvar: privateParams->newfcastvar]; [aForecast setForecast: 0.0]; [aForecast setLforecast: global_mean]; ! //also inside its init, lastactive =1, specificity=0, variance=99999; ! [aForecast setVariance: privateParams->newfcastvar]; //same as bfagent's init [aForecast setStrength: 0.0]; ! /* Set the forecasting parameters for each fcast to random values in a * fraction "subrange" of their range, centered at the midpoint. For * subrange=1 this is the whole range (min to max). For subrange=0.5, * values lie between 1/4 and 3/4 of this range. subrange=0 gives * homogeneous agents, with values at the middle of their min-max range. */ + [aForecast setAval : abase + drand()*asubrange]; [aForecast setBval : bbase + drand()*bsubrange]; [aForecast setCval : cbase + drand()*csubrange]; *************** *** 443,451 **** [fcastObject setConditionsbit: bit FromZeroTo: irand(2)+1]; //remember 1 means no, or binary 01, and 2 means Yes, or 10 [fcastObject incrSpecificity];//pj: I wish this were automatic! - [fcastObject updateSpecfactor]; } } return self; } --- 388,396 ---- [fcastObject setConditionsbit: bit FromZeroTo: irand(2)+1]; //remember 1 means no, or binary 01, and 2 means Yes, or 10 [fcastObject incrSpecificity];//pj: I wish this were automatic! } } + [fcastObject updateSpecfactor]; return self; } *************** *** 473,491 **** BFCast * aForecast; id index; - #if WEIGHTED == 1 - static double a, b, c, sum, sumv; - #else - //struct BF_fcast *bestfptr; BFCast * bestForecast; double maxstrength; ! #endif // First the genetic algorithm is run if due ! currentTime = getCurrentTime( ); ! if (currentTime >= privateParams->firstgatime && drand() < privateParams->gaprob) { [self performGA]; [activeList removeAll]; --- 418,432 ---- BFCast * aForecast; id index; BFCast * bestForecast; double maxstrength; ! double minvar; // First the genetic algorithm is run if due ! currentTime = getCurrentTime()+1; ! if ((currentTime >= privateParams->firstgatime) && (drand() < privateParams->gaprob)) { [self performGA]; [activeList removeAll]; *************** *** 501,610 **** [myworld drop]; //was created inside collectWorldData - #if WEIGHTED == 1 - // Construct weighted-average forecast - // The individual forecasts are: p + d = a(p+d) + b(d) + c - // We often lock b at 0 by setting b_min = b_max = 0. - - //pj: note I started updating this code to match the rest, but then - //pj: I realized it did not work as it was before, so I stopped - //pj: messing with it. Don't expect the CPPFLAG WEIGHTED to do - //pj: anything good. - - a = 0.0; - b = 0.0; - c = 0.0; - sumv = 0.0; - sum = 0.0; - nactive = 0; - mincount = privateParams->mincount; - - index=[ activeList begin: [self getZone] ]; - for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) - { - [aForecast setLastactive: t]; - if ( [aForecast incrCount] >= mincount ) - { - double sumstrength; - double strength; - strength=[aForecast getStrength]; - ++nactive; - - a += strength*[aForecast getAval]; - b += strength*[aForecast getBval] ; - c += strength*[aForecast getCval] ; - sum += strength; - sumv += [aForecast getVariance]; - } - } - [index drop]; - - if (nactive) - { - pdcoeff = a/sum; - offset = (b/sum)*dividend + (c/sum); - forecastvar = privateParams->individual? sumv/((double)nactive) :variance; - } - #else - //NOT WEIGHTED MODEL // Go through the list and find best forecast maxstrength = -1e50; bestForecast = nil; nactive = 0; ! mincount = getInt(privateParams,"mincount"); - //pj: Kept as example of "homemade list" in ASM-2.0 - // for (fptr=activelist; fptr!=NULL; fptr=fptr->next) - // { - // fptr->lastactive = currentTime; - // if (++fptr->count >= mincount) - // { - // ++nactive; - // if (fptr->strength > maxstrength) - // { - // maxstrength = fptr->strength; - // bestfptr = fptr; - // } - // } - // } - - - //??Following code causes a bug when numfcasts is small. It causes - //nactive >0 even though there is no best forecast. ?? Track it down - //This problem existed in ASM-2.0, should back track it. index=[activeList begin: [self getZone]]; for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) { [aForecast setLastactive: currentTime]; if([aForecast incrCount] >= mincount) { - double strength=[aForecast getStrength]; ++nactive; ! if (strength > maxstrength) { ! maxstrength = strength; bestForecast= aForecast; } } } [index drop]; - // Here is the way it was in ASM-2.0 - // if (nactive) - // { - // pdcoeff = bestfptr->a; - // offset = bestfptr->b*dividend + bestfptr->c; - // forecastvar = (privateParams->individual? bestfptr->variance :variance); - // } - if (nactive) // meaning that at least some forecasts are active { pdcoeff = [bestForecast getAval]; offset = [bestForecast getBval]*dividend + [bestForecast getCval]; ! forecastvar = getInt(privateParams,"individual")? [bestForecast getVariance]: variance; } - #endif else // meaning "nactive" zero, no forecasts are active { // No forecasts are minimally adequate!! --- 442,479 ---- [myworld drop]; //was created inside collectWorldData // Go through the list and find best forecast maxstrength = -1e50; + minvar = 1e50; bestForecast = nil; nactive = 0; ! mincount = privateParams->mincount; index=[activeList begin: [self getZone]]; for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) { + //printf(" agent[%d], at time= %d: lastactive=%d count=%d\n",myID,currentTime,[aForecast getLastactive],[aForecast getCnt]); [aForecast setLastactive: currentTime]; if([aForecast incrCount] >= mincount) { ++nactive; ! if ([aForecast getActvar] < minvar) { ! minvar = [aForecast getActvar]; bestForecast= aForecast; } } } [index drop]; if (nactive) // meaning that at least some forecasts are active { pdcoeff = [bestForecast getAval]; offset = [bestForecast getBval]*dividend + [bestForecast getCval]; ! forecastvar = (privateParams->individual? [bestForecast getVariance]: variance); ! [bestForecast setLastused: currentTime]; } else // meaning "nactive" zero, no forecasts are active { // No forecasts are minimally adequate!! *************** *** 612,618 **** countsum = 0.0; pdcoeff = 0.0; offset = 0.0; ! mincount = getInt(privateParams,"mincount"); index = [fcastList begin: [self getZone]]; --- 481,487 ---- countsum = 0.0; pdcoeff = 0.0; offset = 0.0; ! mincount = privateParams->mincount; index = [fcastList begin: [self getZone]]; *************** *** 639,645 **** [index drop]; } ! divisor = getDouble(privateParams,"lambda")*forecastvar; return self; } --- 508,514 ---- [index drop]; } ! divisor = privateParams->lambda*forecastvar; return self; } *************** *** 664,670 **** [world setCondwords: params->condwords]; [world setCondbits: params->condbits]; world=[world createEnd]; ! bitlist = [params getBitListPtr]; nworldbits = [worldForAgent getNumWorldBits]; --- 533,540 ---- [world setCondwords: params->condwords]; [world setCondbits: params->condbits]; world=[world createEnd]; ! [world init]; ! bitlist = [params getBitListPtr]; nworldbits = [worldForAgent getNumWorldBits]; *************** *** 675,681 **** for (i=0; i < params->condbits; i++) { if ((n = bitlist[i]) >= 0) - //myworld[WORD(i)] |= myRealWorld[n] << ((i%16)*2); [world setConditionsbit: i To: myRealWorld[n]]; } --- 545,550 ---- *************** *** 698,855 **** { id index; BFCast * aForecast; ! [self copyList: activeList To: oldActiveList]; //pj: note, if activeList is empty, then oldActiveList will be empty. ! [activeList removeAll]; ! ! //pj:copy forecasted values from objects in active to oldActiveList index=[ oldActiveList begin: [self getZone] ]; ! for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { [aForecast setLforecast: [aForecast getForecast]]; ! } ! [index drop]; ! switch (privateParams->condwords) { case 1: - - index=[ fcastList begin: [self getZone]]; - for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) { ! if ( [aForecast getConditionsWord: 0] & [worldvalues getConditionsWord: 0] ) ! { ! continue ; ! } ! [activeList addLast: aForecast]; } - [index drop]; - - break; - case 2: ! //pj: here is how it used to be in ASM-2.0 ! // real1 = worldvalues[1]; ! ! // for (fptr = fcast; fptr < topfptr; fptr++) ! // { ! // if (fptr->conditions[0] & real0) continue; ! // if (fptr->conditions[1] & real1) continue; ! // *nextptr = fptr; ! // nextptr = &fptr->next; ! // } ! ! index=[ fcastList begin: [self getZone]]; ! for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! if ( [aForecast getConditionsWord: 0] & [worldvalues getConditionsWord: 0] ) continue ; ! if ( [aForecast getConditionsWord: 1] & [worldvalues getConditionsWord: 1] ) continue ; ! [activeList addLast: aForecast]; ! } ! [index drop]; ! break; ! case 3: ! ! index=[ fcastList begin: [self getZone]]; ! for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! if ( [aForecast getConditionsWord: 0] & [worldvalues getConditionsWord: 0] ) continue ; ! if ( [aForecast getConditionsWord: 1] & [worldvalues getConditionsWord: 1] ) continue ; ! if ( [aForecast getConditionsWord: 2] & [worldvalues getConditionsWord: 2] ) continue ; ! [activeList addLast: aForecast]; } - [index drop]; - break; case 4: ! ! index=[ fcastList begin: [self getZone]]; ! for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! if ( [aForecast getConditionsWord: 0] & [worldvalues getConditionsWord: 0]) continue ; ! if ( [aForecast getConditionsWord: 1] & [worldvalues getConditionsWord: 1] ) continue ; ! if ( [aForecast getConditionsWord: 2] & [worldvalues getConditionsWord: 2] ) continue ; ! if ( [aForecast getConditionsWord: 3] & [worldvalues getConditionsWord: 3] ) continue ; ! [activeList addLast: aForecast]; ! } ! [index drop]; break; case 5: ! ! index=[ fcastList begin: [self getZone]]; ! for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! if ( [aForecast getConditionsWord: 0] & [worldvalues getConditionsWord: 0] ) continue ; ! if ( [aForecast getConditionsWord: 1] & [worldvalues getConditionsWord: 1] ) continue ; ! if ( [aForecast getConditionsWord: 2] & [worldvalues getConditionsWord: 2] ) continue ; ! if ( [aForecast getConditionsWord: 3] & [worldvalues getConditionsWord: 3] ) continue ; ! if ( [aForecast getConditionsWord: 4] & [worldvalues getConditionsWord: 4] ) continue ; ! [activeList addLast: aForecast]; ! } ! [index drop]; ! break; ! } ! #if MAXCONDBITS > 5*16 #error Too many condition bits (MAXCONDBITS) #endif ! ! //pj??? There ought to be a "default" action here for other cases. ! ! ! /*This is an alternative implementation of the same as preceeding. ! It is so much cuter in my view. I wrote it before I understood the ! fact that the World gives back 10 for yes and agent has 01 for yes, so ! you have to be careful with it. Note the bitmath here, that appears ! as it used to throughout the BFagent class. ! ! index=[ fcastList begin: [self getZone]]; ! for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! unsigned int flag=0; ! unsigned int trit; ! unsigned int predictedvalue=999; ! ! trit=-1; ! while ( flag == 0 && ++trit < privateParams-> condbits ) ! { ! if ( (predictedvalue=[aForecast getConditionsbit: trit]) != 0 ) ! { ! //if ( predictedvalue == ((worldvalues[WORD(trit)] >> ((trit%16)*2))&3) ) ! if ( predictedvalue == [worldvalues getConditionsbit: trit] ) ! { ! flag=1; ! } ! } ! ! // fprintf(stderr,"trit:%d flag: %d predictionl=%d, world=%d\n", ! // trit, flag, predictedvalue, ! // extractvalue(worldvalues,trit) ); ! } ! ! if ( flag!=1 ) [activeList addLast: aForecast]; ! ! } ! [index drop]; */ ! ! return self; ! } ! ! /*"Currently does nothing, used only if their are ANNagents"*/ ! - getInputValues ! { ! return self; ! } - /*"Currently does nothing, used only if their are ANNagents"*/ - - feedForward - { return self; } --- 567,710 ---- { id index; BFCast * aForecast; + double val = 0; + double strongestBFValue = -1.0; ! //pj: note, if activeList is empty, then oldActiveList will be empty. ! [self copyList: activeList To: oldActiveList]; [activeList removeAll]; ! //pj:copy forecasted values from objects in active to oldActiveList index=[ oldActiveList begin: [self getZone] ]; ! for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { [aForecast setLforecast: [aForecast getForecast]]; ! } ! [index drop]; ! + switch (privateParams->condwords) { case 1: { ! int real0 = [worldvalues getConditionsWord: 0]; ! ! index=[ fcastList begin: [self getZone]]; ! for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! if ( (val = [aForecast getStrength]) > strongestBFValue ) ! { ! strongestBFCast = aForecast; ! strongestBFValue = val; ! } ! if ( [aForecast getConditionsWord: 0] & real0 ) ! { ! continue ; ! } ! [activeList addLast: aForecast]; ! } ! [index drop]; ! ! break; } case 2: ! { ! int * real = [worldvalues getConditions]; ! ! ! index=[ fcastList begin: [self getZone]]; ! for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! int * conditions = [aForecast getConditions]; ! if ( (val = [aForecast getStrength]) > strongestBFValue ) ! { ! strongestBFCast = aForecast; ! strongestBFValue = val; ! } ! if ( conditions[0] & real[0] ) continue ; ! if ( conditions[1] & real[1] ) continue ; ! [activeList addLast: aForecast]; ! } ! [index drop]; ! ! break; ! } ! case 3: ! { ! int * real = [worldvalues getConditions]; ! ! index=[ fcastList begin: [self getZone]]; ! for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! int * conditions = [aForecast getConditions]; ! if ( (val = [aForecast getStrength]) > strongestBFValue ) ! { ! strongestBFCast = aForecast; ! strongestBFValue = val; ! } ! if ( conditions[0] & real[0] ) continue ; ! if ( conditions[1] & real[1] ) continue ; ! if ( conditions[2] & real[2] ) continue ; ! [activeList addLast: aForecast]; ! } ! [index drop]; ! break; } case 4: ! { ! int * real = [worldvalues getConditions]; ! ! index=[ fcastList begin: [self getZone]]; ! for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! int * conditions = [aForecast getConditions]; ! if ( (val = [aForecast getStrength]) > strongestBFValue ) ! { ! strongestBFCast = aForecast; ! strongestBFValue = val; ! } ! if ( conditions[0] & real[0] ) continue ; ! if ( conditions[1] & real[1] ) continue ; ! if ( conditions[2] & real[2] ) continue ; ! if ( conditions[3] & real[3] ) continue ; ! [activeList addLast: aForecast]; ! } ! [index drop]; break; + } case 5: ! { ! int * real = [worldvalues getConditions]; ! index=[ fcastList begin: [self getZone]]; ! for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! int * conditions = [aForecast getConditions]; ! if ( (val = [aForecast getStrength]) > strongestBFValue ) ! { ! strongestBFCast = aForecast; ! strongestBFValue = val; ! } ! if ( conditions [0] & real[0] ) continue ; ! if ( conditions [1] & real[1] ) continue ; ! if ( conditions [2] & real[2] ) continue ; ! if ( conditions [3] & real[3] ) continue ; ! if ( conditions [4] & real[4] ) continue ; ! [activeList addLast: aForecast]; ! } ! [index drop]; ! break; ! } ! } #if MAXCONDBITS > 5*16 #error Too many condition bits (MAXCONDBITS) #endif ! //pj??? There ought to be a "default" action here for other cases. return self; } *************** *** 927,1014 **** - updatePerformance { - //pj: register struct BF_fcast *fptr; BFCast * aForecast; id index = nil; ! 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 = 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; ! ! // Update global mean (p+d) and our variance ! [self getPriceFromWorld]; ftarget = price + dividend; // Update global mean (p+d) and our variance ! realDeviation = deviation = ftarget - lforecast; if (fabs(deviation) > maxdev) deviation = maxdev; 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; ! ! //I cant find anywhere in ASM-2.0's BFagent.m an update of the forecast's ! //forecast. but it is clearly needed if you look at bfagent from the ! //objc version. Including the next loop ! //fixes the strange time series properties too ! ! //printf("active list has %d \n",[activeList getCount] ); ! ! index = [ activeList begin: [self getZone]]; ! for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! [aForecast updateForecastPrice: price Dividend: dividend]; ! } ! [index drop]; ! ! //pj: Here is the way it was ! // Update all the forecasters that were activated. ! // if (currentTime > 0) ! // for (fptr=lactivelist; fptr!=NULL; fptr=fptr->lnext) ! // { ! // deviation = (ftarget - fptr->lforecast)*(ftarget - fptr->lforecast); ! ! // // Benchmark test line - replace true deviation with random one ! // // PARAM: Might be coded as a parameter sometime ! // // deviation = drand(); ! ! // // Only necessary for absolute deviations ! // // if (deviation < 0.0) deviation = -deviation; ! ! // if (deviation > maxdev) deviation = maxdev; ! // if (fptr->count > tauv) ! // fptr->variance = b*fptr->variance + a*deviation; ! // else ! // { ! // c = 1.0/(1.+fptr->count); ! // fptr->variance = (1.0 - c)*fptr->variance + ! // c*deviation; ! // } ! // fptr->strength = fptr->specfactor/fptr->variance; ! // } ! if (currentTime > 0) { index = [ oldActiveList begin: [self getZone]]; for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) --- 782,831 ---- - updatePerformance { BFCast * aForecast; id index = nil; ! double deviation, ftarget, tauv, a, b, c, maxdev; ! ! //printf("price before= %f\n",price); ! [self getPriceFromWorld]; ! //printf("price after= %f\n",price); ! ! index = [ activeList begin: [self getZone]]; ! for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! [aForecast updateForecastPrice: price Dividend: dividend]; ! } ! [index drop]; ! // Precompute things for speed + currentTime = getCurrentTime()+1; tauv = privateParams->tauv; a = 1.0/tauv; b = 1.0-a; /* fixed variance if tauv at max */ if (tauv == 100000) { a = 0.0; b = 1.0; } maxdev = privateParams->maxdev; ! ftarget = price + dividend; // Update global mean (p+d) and our variance ! deviation = ftarget - lforecast; if (fabs(deviation) > maxdev) deviation = maxdev; global_mean = b*global_mean + a*ftarget; ! ! if (currentTime < tauv) variance = privateParams->initvar; ! else ! variance = b*variance + a*deviation*deviation; ! if (currentTime > 1) { index = [ oldActiveList begin: [self getZone]]; for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) *************** *** 1017,1051 **** deviation = (ftarget - lastForecast)*(ftarget - lastForecast); if (deviation > maxdev) deviation = maxdev; ! if ([aForecast getCnt] > tauv) ! [aForecast setVariance : b*[aForecast getVariance] + a*deviation]; else { ! c = 1.0/(double) (1.0 +[aForecast getCnt]); //??bfagent had no 1+ here ?? ! [aForecast setVariance: (1.0 - c)*[aForecast getVariance] + ! c*deviation]; } - - [aForecast setStrength: privateParams->maxdev - - [aForecast getVariance] - + [aForecast getSpecfactor]]; - // ****************************************/ - // pj: The preceeding is based on sfsm's bfagent.m - // - // original bfagent has this: rptr->strength = p->maxdev - - // rptr->variance + rptr->specfactor; - - // BFagent in ASM-2.0 had this: fptr->strength = - // fptr->specfactor/fptr->variance; I've spoken to Blake - // LeBaron and we both like the old way and don't know why it - // was changed. - - // I hasten to say that maxdev is the benchmark for - // variance, and I wonder if maxdev would not be better - // renamed maxdev-squared or maxvar. - //******************************************/ } - [index drop]; } --- 834,847 ---- deviation = (ftarget - lastForecast)*(ftarget - lastForecast); if (deviation > maxdev) deviation = maxdev; ! if ([aForecast getCnt] > 0) ! [aForecast setActvar: b*[aForecast getActvar] + a*deviation]; else { ! c = 1.0/(1.0+[aForecast getCnt]); ! [aForecast setActvar: (1.0 - c)*[aForecast getActvar] + c*deviation]; } } [index drop]; } *************** *** 1058,1070 **** return fabs(realDeviation); } - /*"Currently, does nothing, used only if their are ANNagents"*/ - - updateWeights - { - return self; - } - - /*"Returns the "condbits" variable from parameters: the number of condition bits that are monitored in the world, or 0 if condition bits aren't used. --- 854,859 ---- *************** *** 1083,1101 **** return privateParams->numfcasts; } - /*"Return the last time the Genetic Algorithm was run. - // Agents that don't use a genetic algorithm return MININT. This - // may be used to see if the bit distribution might have changed, - // since a change can only occur through a genetic algorithm."*/ - - (int)lastgatime - { - return lastgatime; - } - - /*"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)"*/ // Original docs from ASM-2.0 // Places in (*countptr)[0] -- (*countptr)[3] the addresses of 4 // arrays, (*countptr)[0][i] -- (*countptr)[3][i], which are filled --- 872,878 ---- *************** *** 1119,1131 **** 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]); --- 896,908 ---- static int countsize = -1; // Current size/4 of count[] static int prevsize = -1; ! condbits = 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]); *************** *** 1143,1212 **** (*countptr)[2] = count[2]; (*countptr)[3] = count[3]; if (!cum) for(i=0;iconditions; ! // 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. --- 920,1020 ---- (*countptr)[2] = count[2]; (*countptr)[3] = count[3]; + currentTime = getCurrentTime()+1; + if (!cum) for(i=0;icondbits; ! currentTime = getCurrentTime()+1; ! medstrength = [self getMedianstrength]; if (!cum) ! for(i=0;i<8;i++) ! moment[i] = 0; ! ! for (i=0;i<8;i++) ! mt[i]=0; ! index=[ fcastList begin: [self getZone] ]; for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) { ! if (((currentTime - [aForecast getLastused]) < 10000) && ([aForecast getStrength] >= medstrength)) ! sumweight += weight = 1; ! else ! weight = 0; ! ! mt[0] += weight*[aForecast getAval]; ! mt[2] += weight*[aForecast getBval]; ! mt[4] += weight*[aForecast getCval]; ! mt[6] += weight*[aForecast getVariance]; ! } ! ! if (sumweight != 0) ! for (i=0;i<8;i+=2) ! mt[i] /= sumweight; ! else ! for (i=0;i<8;i+=2) ! mt[i] = 0; ! ! sumweight = 0; ! ! index=[ fcastList begin: [self getZone] ]; ! for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! if (((currentTime - [aForecast getLastused]) < 10000) && ([aForecast getStrength] >= medstrength)) ! sumweight += weight = 1; ! else ! weight = 0; ! ! mt[1] += weight*fabs([aForecast getAval]-mt[0]); ! mt[3] += weight*fabs([aForecast getBval]-mt[2]); ! mt[5] += weight*fabs([aForecast getCval]-mt[4]); ! mt[7] += weight*fabs([aForecast getVariance]-mt[6]); } + + if (sumweight != 0) + for (i=1;i<8;i+=2) + mt[i] /= sumweight; + else + for (i=1;i<8;i+=2) + mt[i] = 0; + + for (i=0;i<8;i++) + moment[i] += mt[i]; + [index drop]; ! return privateParams->numfcasts; } // ASM-2.0 documentation: // If the agent uses condition bits, returns a description of the // specified bit. Invalid bit numbers return an explanatory message. *************** *** 1214,1220 **** // - (const char *)descriptionOfBit: (int)bit { ! if (bit < 0 || bit > getInt(privateParams,"condbits")) return "(Invalid condition bit)"; else return [World descriptionOfBit:privateParams->bitlist[bit]]; --- 1022,1028 ---- // - (const char *)descriptionOfBit: (int)bit { ! if (bit < 0 || bit > privateParams->condbits) return "(Invalid condition bit)"; else return [World descriptionOfBit:privateParams->bitlist[bit]]; *************** *** 1266,1272 **** - (BFCast *) GetMort: (BFCast *) new Rejects: (id ) rejects ! -(void) Generalize: (id) list AvgStrength: (double) avgstrength // Parameter list: --- 1074,1080 ---- - (BFCast *) GetMort: (BFCast *) new Rejects: (id ) rejects ! -(void) Generalize: (id) list Strength: (double) medstrength // Parameter list: *************** *** 1294,1356 **** // _{ 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++) --- 1102,1230 ---- // _{ genfrac -- fraction of 0/1 bits to make don't-care when generalising} "*/ + + - performGA { int new; ! double madv = 0.0; + //int * bitlist; id newList = [List create: [self getZone]]; //to collect the new forecasts; ! id rejectList = [Array create: [self getZone] setCount: privateParams->npoolmax]; ! double medstrength; ++gacount; ! currentTime = getCurrentTime()+1; ! //bitlist = privateParams->bitlist; + medstrength = [self CalculateMedian]; + medianstrength = medstrength; + // Find the npool weakest rules, for later use in TrnasferFcasts [self MakePool: rejectList From: fcastList]; // Compute average strength (for assignment to new rules) ! madv = [self CalculateAndUseMadv]; ! ! // Loop to construct nnew new rules ! for (new = 0; new < privateParams->nnew; new++) ! { ! BOOL changed = NO; ! BFCast * aNewForecast = [ self createNewForecast ]; ! [aNewForecast init]; ! [newList addLast: aNewForecast]; ! ! // Loop used if we force diversity ! do ! { ! changed = [self PickParents: aNewForecast Strength: medstrength]; ! ! if (changed) ! { ! aNewForecast = [self FcastSetParams: aNewForecast Strength: medstrength Madv: madv]; ! } ! } while (!changed); ! /* 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 Strength: medstrength ]; ! ! [newList deleteAll]; ! [newList drop]; ! [rejectList drop]; ! ! return self; ! } ! ! //************************************************************************+ ! - (double)CalculateMedian //Computes median strength ! { ! double median,strvalues[privateParams->numfcasts]; ! int f,n; ! int medcomp(); ! ! n = privateParams->numfcasts; ! for (f=0; f < n; f++) { BFCast * aForecast = [fcastList atOffset: f]; ! if ([aForecast getCnt] != 0) ! { ! [aForecast setVariance: [aForecast getActvar]]; ! [aForecast setStrength: privateParams->maxdev - [aForecast getVariance] + [aForecast getSpecfactor]]; ! } ! strvalues[f]= [[fcastList atOffset: f] getStrength]; ! } ! qsort(strvalues,n,sizeof(double),medcomp); ! //for (f=0; f 0) ! return(1); ! else ! if( (*x - *y) < 0) ! return(-1); ! else ! return(0); ! } ! ! ! //************************************************************************+ ! - (double)CalculateAndUseMadv ! { ! double madv,ava,avb,avc,sumc,varvalue; ! double meanv = 0.0; ! int f; ! varvalue = madv = ava = avb = avc = sumc = 0.0; ! ! for (f=0; f < privateParams->numfcasts; f++) ! { ! BFCast * aForecast = [fcastList atOffset: f]; ! varvalue= [aForecast getVariance]; meanv += varvalue; if ( [aForecast getCnt] > 0) { if ( varvalue !=0 ) { sumc += 1.0/ varvalue ; ava += [ aForecast getAval ] / varvalue ; avb += [ aForecast getBval ] / varvalue; avc += [ aForecast getCval ] / varvalue ; } } } meanv = meanv/ privateParams->numfcasts; for (f=0; f < privateParams->numfcasts; f++) *************** *** 1360,1368 **** 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 --- 1234,1239 ---- *************** *** 1372,1474 **** [[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, --- 1243,1314 ---- [[fcastList atOffset: 0] setAval: ava/ sumc ]; [[fcastList atOffset: 0] setBval: avb/ sumc ]; [[fcastList atOffset: 0] setCval: avc/ sumc ]; ! return (madv); ! } ! ! //************************************************************************+ ! - (BFCast *)FcastSetParams: (BFCast *)aNewForecast Strength: (double)medstrength Madv: (double)madv ! { ! [aNewForecast setActvar: privateParams->maxdev - [aNewForecast getStrength] + [aNewForecast getSpecfactor]]; ! ! BFCast * zeroForecast = [fcastList atOffset: 0]; ! if ([aNewForecast getActvar] < ([zeroForecast getVariance] - madv)) ! { ! [aNewForecast setActvar: ([zeroForecast getVariance] - madv)]; ! [aNewForecast setStrength: privateParams->maxdev - ([zeroForecast getVariance] - madv) + [aNewForecast getSpecfactor]]; } + + if ([aNewForecast getActvar] <= 0) + { + [aNewForecast setActvar: privateParams->maxdev - medstrength + [aNewForecast getSpecfactor]]; + [aNewForecast setStrength: medstrength]; + } + + [aNewForecast setVariance: [aNewForecast getActvar]]; + [aNewForecast setLastactive: currentTime]; + [aNewForecast setCnt: 0]; + + return aNewForecast; + } ! //************************************************************************+ ! - (BOOL)PickParents: (BFCast *)aNewForecast Strength: (double)medstrength ! { ! BFCast * parent1, * parent2; ! BOOL changed = NO; ! parent1 = nil; ! parent2 = nil; ! // Pick first parent using touranment selection ! 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 Strength: medstrength]; ! 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 Strength: medstrength]; ! } ! ! return changed; } /*"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, *************** *** 1479,1506 **** - (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]]; ! [to setSpecfactor: [from getSpecfactor]]; ! [to setLastactive: [from getLastactive]]; ! [to setSpecificity: [from getSpecificity]]; ! [to setConditions: [from getConditions]]; ! [to setCnt: [from getCnt]]; ! if ( [from getCnt] ==0) ! [to setStrength: 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: (id )rejects From: (id )list { register int top; int i,j = 0 ; --- 1319,1348 ---- - (BFCast *)CopyRule: (BFCast *)to From: (BFCast *)from { ! [to setForecast: [from getForecast]]; ! [to setLforecast: [from getLforecast]]; ! [to setVariance: [from getVariance]]; ! [to setActvar: [from getActvar]]; ! [to setStrength: [from getStrength]]; ! [to setAval: [from getAval]]; ! [to setBval: [from getBval]]; ! [to setCval: [from getCval]]; ! [to setSpecfactor: [from getSpecfactor]]; ! [to setLastactive: [from getLastactive]]; ! [to setSpecificity: [from getSpecificity]]; ! [to setConditions: [from getConditions]]; ! [to setCnt: [from getCnt]]; return to; } + /*------------------------------------------------------*/ + /* MakePool */ + /*------------------------------------------------------*/ /*"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: (id)rejects From: (id)list { register int top; int i,j = 0 ; *************** *** 1509,1515 **** top = -1; //pj: why not just start at 1 so we never worry about putting forecast 0 into the mix? ! for ( i=1; i < getInt(privateParams,"npool" ); i++ ) { aForecast=[list atOffset: i]; for ( j=top; j >= 0 && (aReject=[rejects atOffset:j])&& ([aForecast getStrength] < [aReject getStrength] ); j--) --- 1351,1357 ---- top = -1; //pj: why not just start at 1 so we never worry about putting forecast 0 into the mix? ! for ( i=1; i <= privateParams->npool ; i++ ) { aForecast=[list atOffset: i]; for ( j=top; j >= 0 && (aReject=[rejects atOffset:j])&& ([aForecast getStrength] < [aReject getStrength] ); j--) *************** *** 1519,1526 **** [rejects atOffset: j+1 put: aForecast]; top++; } ! ! for ( ; i < getInt(privateParams,"numfcasts"); i++) { aForecast=[list atOffset: i]; if ( [aForecast getStrength] < [[ rejects atOffset: top] getStrength ] ) --- 1361,1368 ---- [rejects atOffset: j+1 put: aForecast]; top++; } ! ! for ( ; i < privateParams->numfcasts; i++) { aForecast=[list atOffset: i]; if ( [aForecast getStrength] < [[ rejects atOffset: top] getStrength ] ) *************** *** 1529,1538 **** { [rejects atOffset: j+1 put: aReject]; } } - [rejects atOffset: j+1 put: aForecast]; } - //pj:note: we are not checking to see if forecast 0 is in here } --- 1371,1379 ---- { [rejects atOffset: j+1 put: aReject]; } + [rejects atOffset: j+1 put: aForecast]; } } } *************** *** 1541,1557 **** /*------------------------------------------------------*/ /* Tournament */ /*------------------------------------------------------*/ ! - (BFCast *) Tournament: (id ) list { ! int numfcasts=[list getCount]; ! BFCast * candidate1 = [list atOffset: irand(numfcasts)]; ! BFCast * candidate2; ! do ! candidate2 = [list atOffset: irand(numfcasts)]; ! while (candidate2 == candidate1); ! if ([candidate1 getStrength] > [candidate2 getStrength]) return candidate1; else --- 1382,1410 ---- /*------------------------------------------------------*/ /* Tournament */ /*------------------------------------------------------*/ ! - (BFCast *) Tournament: (id) list { ! int i,numfcasts=[list getCount]; ! BFCast * candidate1; ! BFCast * candidate2; ! i=0; do ! { ! candidate1 = [list atOffset: irand(numfcasts)]; ! i++; ! } ! while (([candidate1 getCnt] == 0) && (i<50)); ! ! i=0; ! ! do ! { ! candidate2 = [list atOffset: irand(numfcasts)]; ! i++; ! } ! while (([candidate2 getCnt] == 0) || ((candidate2 == candidate1) && (i<50))); ! if ([candidate1 getStrength] > [candidate2 getStrength]) return candidate1; else *************** *** 1564,1570 **** /*------------------------------------------------------*/ /* Mutate */ /*------------------------------------------------------*/ ! - (BOOL)Mutate: (BFCast *)new Status: (BOOL)changed /* * For the condition bits, Mutate() looks at each bit with * probability pmutation. If chosen, a bit is changed as follows: --- 1417,1423 ---- /*------------------------------------------------------*/ /* Mutate */ /*------------------------------------------------------*/ ! - (BOOL)Mutate: (BFCast *)new Status: (BOOL)changed Strength: (double)medstrength /* * For the condition bits, Mutate() looks at each bit with * probability pmutation. If chosen, a bit is changed as follows: *************** *** 1600,1608 **** double choice, temp; BOOL bitchanged = NO; int * bitlist= NULL; - bitlist= [privateParams getBitListPtr]; - //pj: dont know why BFagents introduced bitchanged.?? bitchanged = changed; if (privateParams->pmutation > 0) { --- 1453,1462 ---- double choice, temp; BOOL bitchanged = NO; int * bitlist= NULL; + int selmutate; + + bitlist = [privateParams getBitListPtr]; bitchanged = changed; if (privateParams->pmutation > 0) { *************** *** 1611,1638 **** if (bitlist[bit] < 0) continue; if (drand() < privateParams->pmutation) { - //cond = cond0 + WORD(bit); - //if (*cond & MASK[bit]) if ([new getConditionsbit: bit] > 0 ) { if (irand(3) > 0) { - // *cond &= NMASK[bit]; - //nr->specificity--; [new maskConditionsbit: bit]; [new decrSpecificity]; } else - // *cond ^= MASK[bit]; [new switchConditionsbit: bit]; - bitchanged = changed = YES; } else if (irand(3) > 0) { - - // *cond |= (irand(2)+1) << SHIFT[bit]; - // nr->specificity++; [new setConditionsbit: bit FromZeroTo: (irand(2)+1)]; [new incrSpecificity]; bitchanged = changed = YES; --- 1465,1483 ---- *************** *** 1640,1653 **** } } } ! /* mutate p+d coefficient */ choice = drand(); if (choice < privateParams->plong) { /* long jump = uniform distribution between min and max */ [new setAval: privateParams->a_min + privateParams->a_range*drand()] ; ! changed = YES; } else if (choice < privateParams->plong + privateParams->pshort) { --- 1485,1499 ---- } } } ! ! selmutate = irand(2); /* mutate p+d coefficient */ choice = drand(); if (choice < privateParams->plong) { /* long jump = uniform distribution between min and max */ [new setAval: privateParams->a_min + privateParams->a_range*drand()] ; ! if (privateParams->a_range != 0) changed = YES; } else if (choice < privateParams->plong + privateParams->pshort) { *************** *** 1655,1661 **** temp = [new getAval] + privateParams->a_range*privateParams->nhood*urand(); [new setAval: (temp > privateParams->a_max? privateParams->a_max: (temp < privateParams->a_min? privateParams->a_min: temp))]; ! changed = YES; } /* else leave alone */ --- 1501,1507 ---- temp = [new getAval] + privateParams->a_range*privateParams->nhood*urand(); [new setAval: (temp > privateParams->a_max? privateParams->a_max: (temp < privateParams->a_min? privateParams->a_min: temp))]; ! if (privateParams->a_range != 0) changed = YES; } /* else leave alone */ *************** *** 1665,1671 **** { /* long jump = uniform distribution between min and max */ [new setBval: privateParams->b_min + privateParams->b_range*drand() ]; ! changed = YES; } else if (choice < privateParams->plong + privateParams->pshort) { --- 1511,1517 ---- { /* long jump = uniform distribution between min and max */ [new setBval: privateParams->b_min + privateParams->b_range*drand() ]; ! if (privateParams->b_range != 0) changed = YES; } else if (choice < privateParams->plong + privateParams->pshort) { *************** *** 1673,1679 **** temp = [new getBval] + privateParams->b_range*privateParams->nhood*urand(); [new setBval: (temp > privateParams->b_max? privateParams->b_max: (temp < privateParams->b_min? privateParams->b_min: temp))]; ! changed = YES; } /* else leave alone */ --- 1519,1525 ---- temp = [new getBval] + privateParams->b_range*privateParams->nhood*urand(); [new setBval: (temp > privateParams->b_max? privateParams->b_max: (temp < privateParams->b_min? privateParams->b_min: temp))]; ! if (privateParams->b_range != 0) changed = YES; } /* else leave alone */ *************** *** 1683,1689 **** { /* long jump = uniform distribution between min and max */ [new setCval: privateParams->c_min + privateParams->c_range*drand()]; ! changed = YES; } else if (choice < privateParams->plong + privateParams->pshort) { --- 1529,1535 ---- { /* long jump = uniform distribution between min and max */ [new setCval: privateParams->c_min + privateParams->c_range*drand()]; ! if (privateParams->c_range != 0) changed = YES; } else if (choice < privateParams->plong + privateParams->pshort) { *************** *** 1691,1705 **** temp = [new getCval] + privateParams->c_range*privateParams->nhood*urand(); [new setCval: (temp > privateParams->c_max? privateParams->c_max: (temp < privateParams->c_min? privateParams->c_min: temp))]; ! changed = YES; } /* else leave alone */ ! [new setCnt: 0]; ! if (changed) { [new updateSpecfactor]; } return(changed); } --- 1537,1555 ---- temp = [new getCval] + privateParams->c_range*privateParams->nhood*urand(); [new setCval: (temp > privateParams->c_max? privateParams->c_max: (temp < privateParams->c_min? privateParams->c_min: temp))]; ! if (privateParams->c_range != 0) changed = YES; } /* else leave alone */ ! if (changed) { [new updateSpecfactor]; + if (([new getCnt]==0) || ((currentTime - [new getLastactive]) > privateParams->longtime)) + [new setStrength: medstrength]; + else + if (bitchanged) + [new setStrength: medstrength]; } return(changed); } *************** *** 1709,1715 **** /*------------------------------------------------------*/ /* Crossover */ /*------------------------------------------------------*/ ! - (BFCast *)Crossover: (BFCast *)newForecast Parent1: (BFCast *)parent1 Parent2: (BFCast *)parent2 /* * On the condition bits, Crossover() uses uniform crossover -- each * bit is chosen randomly from one parent or the other. --- 1559,1565 ---- /*------------------------------------------------------*/ /* Crossover */ /*------------------------------------------------------*/ ! - (BFCast *)Crossover: (BFCast *)newForecast Parent1: (BFCast *)parent1 Parent2: (BFCast *)parent2 Strength: (double)medstrength /* * On the condition bits, Crossover() uses uniform crossover -- each * bit is chosen randomly from one parent or the other. *************** *** 1726,1732 **** { /* Uniform crossover of condition bits */ register int bit; - // unsigned int *cond1, *cond2, *newcond; int word; double weight1, weight2, choice; --- 1576,1581 ---- *************** *** 1734,1743 **** for (word = 0; word condwords; word++) [newForecast setConditionsWord: word To: 0]; ! for (bit = 0; bit < privateParams->condbits; bit++) { ! if ( irand(2) == 0) { int value=[parent1 getConditionsbit: bit]; [newForecast setConditionsbit: bit FromZeroTo: value]; --- 1583,1592 ---- for (word = 0; word condwords; word++) [newForecast setConditionsWord: word To: 0]; ! for (bit = 0; bit < privateParams->condbits; bit++) { ! if ( irand(2) == 0) { int value=[parent1 getConditionsbit: bit]; [newForecast setConditionsbit: bit FromZeroTo: value]; *************** *** 1756,1763 **** if (choice < privateParams->plinear) { /* Crossover method 1 -- linear combination */ ! weight1 = [parent1 getStrength] / ([parent1 getStrength] + ! [parent2 getStrength]); weight2 = 1.0-weight1; [ newForecast setAval: weight1*[parent1 getAval] + weight2*[parent2 getAval] ]; [ newForecast setBval: weight1*[parent1 getBval] + weight2*[parent2 getBval] ]; --- 1605,1613 ---- if (choice < privateParams->plinear) { /* Crossover method 1 -- linear combination */ ! if (([parent1 getVariance]>0) && ([parent2 getVariance]>0)) ! weight1 = (1.0/[parent1 getVariance]) / (1.0/[parent1 getVariance] + 1.0/[parent2 getVariance]); ! else weight1 = 0.5; weight2 = 1.0-weight1; [ newForecast setAval: weight1*[parent1 getAval] + weight2*[parent2 getAval] ]; [ newForecast setBval: weight1*[parent1 getBval] + weight2*[parent2 getBval] ]; *************** *** 1790,1840 **** } } ! { //This is just error checking! ! BitVector * newcond; ! int specificity=0; ! [newForecast setCnt: 0 ]; // call it new in any case ! ! [newForecast updateSpecfactor]; ! ! [newForecast setStrength : 0.5*([parent1 getStrength] + [parent2 getStrength])]; ! //pj: next steps are purely diagnostic! ! newcond = [newForecast getConditionsObject]; ! for (bit = 0; bit < privateParams->condbits; bit++) ! ! //if ((newcond[WORD(bit)]& ( 3 << ((bit%16)*2))) != 0) ! if ( [newcond getConditionsbit: bit] != 0 ) ! { ! specificity++; ! } ! //printf("CrossoverDiagnostic: newforecast Specificity %d should equal %d \n", [newForecast getSpecificity],specificity); ! } ! return newForecast; } /*------------------------------------------------------*/ /* TransferFcasts */ /*------------------------------------------------------*/ ! - (void)TransferFcastsFrom: newlist To: forecastList Replace: rejects { id ind; BFCast * aForecast; BFCast * toDieForecast; ! //nnew = pp->nnew; ! ! ind = [newlist begin: [self getZone]]; ! for ( aForecast = [ind next]; [ind getLoc]==Member; aForecast=[ind next] ) { ! //toDieForecast = GetMort(aForecast, rejects); ! toDieForecast = [self GetMort: aForecast Rejects: rejects]; ! toDieForecast = [self CopyRule: toDieForecast From: aForecast]; } - [ind drop]; } --- 1640,1703 ---- } } ! ! if ([parent1 getCnt] < [parent2 getCnt]) ! [newForecast setCnt: [parent1 getCnt]]; ! else [newForecast setCnt: [parent2 getCnt]]; + [newForecast setLastactive: (([parent1 getLastactive]+[parent2 getLastactive])/2)]; + + [newForecast updateSpecfactor]; ! if (( (currentTime - [parent1 getLastactive]) > privateParams->longtime) || ! ((currentTime - [parent2 getLastactive]) > privateParams->longtime) || ! ([parent1 getCnt]*[parent2 getCnt]==0)) ! [newForecast setStrength: medstrength]; ! else ! [newForecast setStrength : 0.5*([parent1 getStrength] + [parent2 getStrength])]; ! return newForecast; } /*------------------------------------------------------*/ /* TransferFcasts */ /*------------------------------------------------------*/ ! - (void)TransferFcastsFrom: (id)newlist To: (id)forecastList Replace: (id)rejects { id ind; BFCast * aForecast; BFCast * toDieForecast; + int newcount = 0 , rejectcount = 0; ! if ( (newcount = [newlist getCount]) < (rejectcount= [rejects getCount])) ! { ! ind = [newlist begin: [self getZone]]; ! for ( aForecast = [ind next]; [ind getLoc]==Member; aForecast=[ind next] ) ! { ! toDieForecast = [self GetMort: aForecast Rejects: rejects]; ! toDieForecast = [self CopyRule: toDieForecast From: aForecast]; ! } ! [ind drop]; ! } ! else if ( newcount == rejectcount) ! { ! //copy all newforecasts to replace rejects ! int i; ! for ( i = 0; i < newcount; i++) ! { ! toDieForecast = [rejects atOffset: i]; ! //printf("replaced strength=%f\n",[toDieForecast getStrength]); ! [rejects atOffset: i put: nil]; ! aForecast = [newlist atOffset: i]; ! toDieForecast = [self CopyRule: toDieForecast From: aForecast]; ! } ! } ! else { ! printf("newcount=%d, rejectcount=%d \n",newcount,rejectcount); ! raiseEvent(InvalidArgument,"npool smaller than nnew, can't do it"); } } *************** *** 1842,1848 **** /*------------------------------------------------------*/ /* GetMort */ /*------------------------------------------------------*/ ! - (BFCast *)GetMort: (BFCast *)new Rejects: (id )rejects /* GetMort() selects one of the npool weak old fcasts to replace * with a newly generated rule. It pays no attention to strength, * but looks at similarity of the condition bits -- like tournament --- 1705,1711 ---- /*------------------------------------------------------*/ /* GetMort */ /*------------------------------------------------------*/ ! - (BFCast *)GetMort: (BFCast *)new Rejects: (id)rejects /* GetMort() selects one of the npool weak old fcasts to replace * with a newly generated rule. It pays no attention to strength, * but looks at similarity of the condition bits -- like tournament *************** *** 1851,1888 **** * more diversity. */ { ! //register int bit, temp1, temp2, different1, different2; ! // struct BF_fcast *fptr; ! //unsigned int *cond1, *cond2, *newcond; ! //int npool, r1, r2, word, bitmax; ! unsigned int *cond1; unsigned int *cond2; unsigned int * newcond; int numrejects, r1, r2, word, bitmax = 0; int bit, different1, different2, temp1, temp2; BFCast * aReject; numrejects = privateParams->npool; ! //npool=[reject getCount]; ! do { r1 = irand(numrejects); } while ( [rejects atOffset: r1] == nil ); ! ! do { r2 = irand(numrejects); } while (r1 == r2 || [rejects atOffset: r2] == nil); ! cond1 = [[rejects atOffset: r1] getConditions]; cond2 = [[rejects atOffset: r2] getConditions]; ! newcond = [new getConditions]; ! different1 = 0; different2 = 0; bitmax = 16; --- 1714,1746 ---- * more diversity. */ { ! unsigned int *cond1; unsigned int *cond2; unsigned int * newcond; int numrejects, r1, r2, word, bitmax = 0; int bit, different1, different2, temp1, temp2; BFCast * aReject; numrejects = privateParams->npool; ! do { r1 = irand(numrejects); } while ( [rejects atOffset: r1] == nil ); ! ! do { r2 = irand(numrejects); } while (r1 == r2 || [rejects atOffset: r2] == nil); ! cond1 = [[rejects atOffset: r1] getConditions]; cond2 = [[rejects atOffset: r2] getConditions]; ! newcond = [new getConditions]; ! different1 = 0; different2 = 0; bitmax = 16; *************** *** 1902,1911 **** } /* ! * This is the big decision whether to push diversity by selecting rules ! * to leave. Original version is 1 which choses the least different rules ! * to leave. Version 2 choses at random, and version 3 choses the least ! * frequently used rule. */ if (different1 < different2) { --- 1760,1770 ---- } /* ! * This is the big decision whether to push diversity by selecting ! * rules to leave. Originally there were three versions: Version 1 ! * which choses the least different rules to leave. Version 2 ! * choses at random, and version 3 choses the least frequently used ! * rule. Only version 1 is left. */ if (different1 < different2) { *************** *** 1925,1986 **** /*------------------------------------------------------*/ /* Generalize */ /*------------------------------------------------------*/ ! - (void)Generalize: (id)list AvgStrength: (double)avgstrength /* * Each forecast that hasn't be used for longtime is generalized by * turning a fraction genfrac of the 0/1 bits to don't-cares. */ { ! register struct BFCast *aForecast; ! register int f; int bit, j; BOOL changed; - // int currentTime; int * bitlist = NULL; bitlist = [privateParams getBitListPtr]; - currentTime = getCurrentTime(); - for (f = 0; f < privateParams->numfcasts; f++) { aForecast = [ list atOffset: f ] ; ! if (currentTime - [aForecast getLastactive] > privateParams->longtime) { changed = NO; j = (int)ceil([aForecast getSpecificity]*privateParams->genfrac); ! for (;j>0;) { bit = irand(privateParams->condbits); if (bitlist[bit] < 0) continue; ! // if ((aForecast->conditions[WORD(bit)]&MASK[bit])) ! if ( [aForecast getConditionsbit: bit] > 0) ! { ! // aForecast->conditions[WORD(bit)] &= NMASK[bit]; ! [aForecast maskConditionsbit: bit]; ! [aForecast decrSpecificity]; ! changed = YES; ! j--; } } if (changed) { - double varvalue; [aForecast setCnt: 0]; [aForecast setLastactive: currentTime]; [aForecast updateSpecfactor]; ! //ASM2.0 would be like this: ! // [aForecast setVariance: [aForecast getSpecfactor] / avgstrength]; ! //ASM2.0 would have us do it like this: ! //[aForecast setStrength: [aForecast getSpecfactor]/[aForecast getVariance]]; ! ! //I rather think that, following sfsm, it would be this: ! varvalue = privateParams->maxdev - avgstrength + [aForecast getSpecfactor]; ! if (varvalue >0 ){ ! [aForecast setVariance: varvalue]; ! } ! //apparently don't change variance otherwise ! ! [aForecast setStrength: avgstrength]; } } } --- 1784,1832 ---- /*------------------------------------------------------*/ /* Generalize */ /*------------------------------------------------------*/ ! - (void)Generalize: (id)list Strength: (double)medstrength /* * Each forecast that hasn't be used for longtime is generalized by * turning a fraction genfrac of the 0/1 bits to don't-cares. */ { ! BFCast *aForecast; ! int f; int bit, j; BOOL changed; int * bitlist = NULL; bitlist = [privateParams getBitListPtr]; for (f = 0; f < privateParams->numfcasts; f++) { aForecast = [ list atOffset: f ] ; ! if ((currentTime - [aForecast getLastactive]) > privateParams->longtime) { changed = NO; j = (int)ceil([aForecast getSpecificity]*privateParams->genfrac); ! for (;j>0;) { bit = irand(privateParams->condbits); if (bitlist[bit] < 0) continue; ! if ([aForecast getConditionsbit: bit] > 0) ! { ! [aForecast maskConditionsbit: bit]; ! [aForecast decrSpecificity]; ! changed = YES; ! j--; } } if (changed) { [aForecast setCnt: 0]; [aForecast setLastactive: currentTime]; [aForecast updateSpecfactor]; ! [aForecast setActvar: privateParams->maxdev - medstrength + [aForecast getSpecfactor]]; ! if ([aForecast getActvar] < 0 ) ! [aForecast setActvar: [aForecast getVariance]]; ! [aForecast setVariance: [aForecast getActvar]]; ! [aForecast setStrength: medstrength]; } } } *************** *** 2027,2032 **** --- 1873,1933 ---- } + /*"Save state of BFagent"*/ + - (void)lispOutDeep: stream + { + //If modelType == 0, you need this + [stream catStartMakeInstance: "BFagent"]; + [self bareLispOutDeep: stream]; + [stream catEndMakeInstance]; + } + + /*"Subclasses need to archive variables in here, + but we dont want to create an BFagent class."*/ + + - (void)bareLispOutDeep: stream + { + [super bareLispOutDeep: stream]; + [self lispSaveStream: stream Integer: "currentTime" Value: currentTime ]; + [self lispSaveStream: stream Double: "forecast" Value: forecast ]; + [self lispSaveStream: stream Double: "lforecast" Value: lforecast ]; + + [self lispSaveStream: stream Double: "global_mean" Value: global_mean ]; + [self lispSaveStream: stream Double: "realDeviation" Value: realDeviation ]; + + [self lispSaveStream: stream Double: "variance" Value: variance ]; + [self lispSaveStream: stream Double: "pdcoeff" Value: pdcoeff ]; + [self lispSaveStream: stream Double: "offset" Value: offset ]; + [self lispSaveStream: stream Double: "divisor" Value: divisor ]; + [self lispSaveStream: stream Integer: "gacount" Value: gacount ]; + + + [stream catSeparator]; + [stream catKeyword: "privateParams"]; + [stream catSeparator]; + [privateParams lispOutDeep: stream]; + + + + [stream catSeparator]; + [stream catKeyword: "fcastList"]; + [stream catSeparator]; + [fcastList lispOutDeep: stream]; + + + [stream catSeparator]; + [stream catKeyword: "activeList"]; + [stream catSeparator]; + [activeList lispOutDeep: stream]; + + [stream catSeparator]; + [stream catKeyword: "oldActiveList"]; + [stream catSeparator]; + [oldActiveList lispOutDeep: stream]; + + } + + @end diff -rc ASM-2.2.1/BFCast.h ASM-2.4/BFCast.h *** ASM-2.2.1/BFCast.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/BFCast.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 8,29 **** double forecast; /*" this forecast of return"*/ double lforecast; /*" previous forecast"*/ double variance; /*" variance of this forecast"*/ ! double strength; /*"strength=maxdev - variance +specfactor. This was the original sfsm specification, not the ASM-2.0 specification"*/ double a; /*" (price + dividend) coefficient"*/ double b; /*" dividend coefficient "*/ double c; /*" constant term"*/ double specfactor; /*" specificty=(condbits - nnulls - specificity)* bitcost. "*/ double bitcost; /*" cost of using bits in forecasts"*/ - - BitVector *conditions; /*" a BitVector object that holds records on which conditions in the world are being monitored by this forecast object"*/ int lastactive; /*" last time period in which this forecast was active"*/ int specificity; /*" specificity "*/ int count; /*" number of times this forecast has been active"*/ int condwords; /*"number of words of memory needed to hold the conditions"*/ int condbits; /*"number of bits of information monitored by this forecast"*/ int nnulls; /*"number of 'unused' bits that remain in the allocated vector after the 'condbits' bits have been used"*/ }; - createEnd; --- 8,33 ---- double forecast; /*" this forecast of return"*/ double lforecast; /*" previous forecast"*/ double variance; /*" variance of this forecast"*/ ! double actvar; /*"actual variance of this forecast"*/ ! double strength; /*"strength=maxdev - variance +specfactor.*/ double a; /*" (price + dividend) coefficient"*/ double b; /*" dividend coefficient "*/ double c; /*" constant term"*/ double specfactor; /*" specificty=(condbits - nnulls - specificity)* bitcost. "*/ double bitcost; /*" cost of using bits in forecasts"*/ int lastactive; /*" last time period in which this forecast was active"*/ + int lastused; int specificity; /*" specificity "*/ int count; /*" number of times this forecast has been active"*/ int condwords; /*"number of words of memory needed to hold the conditions"*/ int condbits; /*"number of bits of information monitored by this forecast"*/ int nnulls; /*"number of 'unused' bits that remain in the allocated vector after the 'condbits' bits have been used"*/ + BitVector *conditions; /*" a BitVector object that holds records on which conditions in the world are being monitored by this forecast object"*/ }; + + init; + + - init; - createEnd; *************** *** 81,86 **** --- 85,94 ---- - (double)getVariance; + - (void)setActvar: (double) x; + + - (double)getActvar; + - (void)setCondwords: (int)x; - (void)setCondbits: (int)x; *************** *** 99,104 **** --- 107,116 ---- - (int)getLastactive; + - (void)setLastused: (int)x; + + - (int)getLastused; + - (void)setCnt: (int)x; - (int)getCnt; diff -rc ASM-2.2.1/BFCast.m ASM-2.4/BFCast.m *** ASM-2.2.1/BFCast.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/BFCast.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 14,41 **** - createEnd { ! if (!condwords || !condbits ){fprintf(stderr,"Must have condwords to create BFCast."); exit(1);} forecast= 0.0; count = 0; ! lastactive=1; specificity = 0; variance = 999999999; conditions= [ BitVector createBegin: [self getZone] ]; [conditions setCondwords: condwords]; [conditions setCondbits: condbits]; conditions = [conditions createEnd]; return self; } - /*"The init is needed because BitVector has to be told how bit of a - bit vector it will need"*/ - + init - { - [BitVector init]; - return self; - } - /*"Free dynamically allocated memory"*/ - (void)drop { --- 14,47 ---- - createEnd { ! return self; ! } ! ! /*"The init is needed because BitVector has to be told how big of a ! bit vector it will need"*/ ! + init ! { ! [BitVector init]; ! return self; ! } ! + - init + { forecast= 0.0; count = 0; ! lastactive = lastused = 1; specificity = 0; variance = 999999999; + if (!condwords || !condbits ){fprintf(stderr,"BFCast: Must have condwords to create BFCast."); exit(1);} conditions= [ BitVector createBegin: [self getZone] ]; [conditions setCondwords: condwords]; [conditions setCondbits: condbits]; conditions = [conditions createEnd]; + [conditions init]; return self; } /*"Free dynamically allocated memory"*/ - (void)drop { *************** *** 174,194 **** } /*"Update the spec factor of this forecast. That means calculate: ! specfactor= (condbits - nnulls - specificity)* bitcost "*/ - (void)updateSpecfactor { ! //was in BFagent: specfactor = 1.0/(1.0 + x*specificity); ! //but the bfagent.m way is so much nicer ! specfactor = (condbits - nnulls - specificity)* bitcost; //follows bfagent.m ! } /*"Set the specfactor value of this forecast"*/ - (void)setSpecfactor: (double)x { specfactor = x; ! }; /*"Return the specfactor value of this forecast"*/ - (double)getSpecfactor --- 180,197 ---- } /*"Update the spec factor of this forecast. That means calculate: ! specfactor= (condbits - specificity)* bitcost "*/ - (void)updateSpecfactor { ! specfactor = (condbits - specificity)* bitcost; } /*"Set the specfactor value of this forecast"*/ - (void)setSpecfactor: (double)x { specfactor = x; ! } /*"Return the specfactor value of this forecast"*/ - (double)getSpecfactor *************** *** 232,237 **** --- 235,252 ---- return variance; } + /*"Set the actual variance of this forecast"*/ + - (void)setActvar: (double)x + { + actvar=x; + } + + /*"Return the variance of this forecast"*/ + - (double)getActvar + { + return actvar; + } + /*"Set the time on which this forecast was last active to an input value"*/ - (void)setLastactive: (int)x *************** *** 246,251 **** --- 261,279 ---- } + /*"Set the time on which this forecast was last active to an input value"*/ + - (void)setLastused: (int)x + { + lastused = x; + } + + /*"Return the time on which this forecast was last active"*/ + - (int)getLastused + { + return lastused; + + } + /*"Return the value of count"*/ - (int)getCnt { *************** *** 320,325 **** --- 348,354 ---- forecast = [from getForecast]; lforecast = [from getLforecast]; variance = [from getVariance]; + actvar = [from getActvar]; strength = [from getStrength]; a= [from getAval]; b= [from getBval]; *************** *** 352,359 **** } - - @end --- 381,386 ---- diff -rc ASM-2.2.1/BFParams.h ASM-2.4/BFParams.h *** ASM-2.2.1/BFParams.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/BFParams.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 43,48 **** --- 43,50 ---- double poolfrac; /*" fraction of rules in replacement pool"*/ double newfrac; /*" fraction of rules replaced"*/ double pcrossover; /*" probability of running Crossover()."*/ + double psocial; /*" probability for social behaviour of the agents."*/ + int startsocial; /*" beginning of social behaviour."*/ double plinear; /*" linear combination "crossover" prob."*/ double prandom; /*" random from each parent crossover prob."*/ double pmutation; /*" per bit mutation prob."*/ *************** *** 54,66 **** int npool; /*" derived: replacement pool size"*/ int nnew; /*" derived: number of new rules"*/ int nnulls; /*" unnused bits"*/ - int *bitlist; /*" dynamic array, length condbits"*/ - double *problist; /*" dynamic array, length condbits"*/ - int npoolmax ; /* size of reject array */ int nnewmax ; /* size of newfcast array */ int ncondmax; /* size of newc*/ ! }; --- 56,67 ---- int npool; /*" derived: replacement pool size"*/ int nnew; /*" derived: number of new rules"*/ int nnulls; /*" unnused bits"*/ int npoolmax ; /* size of reject array */ int nnewmax ; /* size of newfcast array */ int ncondmax; /* size of newc*/ ! int *bitlist; /*" dynamic array, length condbits"*/ ! double *problist; /*" dynamic array, length condbits"*/ ! }; *************** *** 74,79 **** --- 75,83 ---- - (void)copyProbList: (double *) p Length: (int) size; - (BFParams *) copy: (id ) aZone; + + - (void)lispOutDeep: stream; + @end diff -rc ASM-2.2.1/BFParams.m ASM-2.4/BFParams.m *** ASM-2.2.1/BFParams.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/BFParams.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 43,57 **** return [probe createEnd]; } - double - getDouble (id obj, const char *ivarName) - { - id probe = makeProbe (obj, ivarName); - double ret = [probe probeAsDouble: obj]; - [probe drop]; - return ret; - } - int getInt (id obj, const char *ivarName) { --- 43,48 ---- *************** *** 152,167 **** bits[3] = ReadBitname("pr/d>7/8", specialbits); bits[4] = ReadBitname("pr/d>1", specialbits); bits[5] = ReadBitname("pr/d>9/8", specialbits); ! bits[6] = ReadBitname("pr/d>5/4", specialbits); ! bits[7] = ReadBitname("pr/d>3/2", specialbits); ! bits[8] = ReadBitname("pr/d>2", specialbits); ! bits[9] = ReadBitname("pr/d>4", specialbits); ! bits[10] = ReadBitname("p>p5", specialbits); ! bits[11] = ReadBitname("p>p20", specialbits); ! bits[12] = ReadBitname("p>p100", specialbits); ! bits[13] = ReadBitname("p>p500", specialbits); ! bits[14] = ReadBitname("on", specialbits); ! bits[15] = ReadBitname("off", specialbits); } else { --- 143,154 ---- bits[3] = ReadBitname("pr/d>7/8", specialbits); bits[4] = ReadBitname("pr/d>1", specialbits); bits[5] = ReadBitname("pr/d>9/8", specialbits); ! bits[6] = ReadBitname("p>p5", specialbits); ! bits[7] = ReadBitname("p>p20", specialbits); ! bits[8] = ReadBitname("p>p100", specialbits); ! bits[9] = ReadBitname("p>p500", specialbits); ! bits[10] = ReadBitname("on", specialbits); ! bits[11] = ReadBitname("off", specialbits); } else { *************** *** 184,194 **** condwords = (condbits+15)/16; - // myworld = [[self getZone] allocBlock: condwords* sizeof(unsigned int)]; - - // for (i=0; i< condwords; i++) - // myworld[i] = 0; - // Check bitcost isn't too negative if (1.0+bitcost*(condbits-nnulls) <= 0.0) printf("The bitcost is too negative."); --- 171,176 ---- *************** *** 206,212 **** if (npool > npoolmax) npoolmax = npool; if (nnew > nnewmax) nnewmax = nnew; if (condwords > ncondmax) ncondmax = condwords; ! // fprintf(stderr,"BFParams init complete"); return [super createEnd]; } --- 188,194 ---- if (npool > npoolmax) npoolmax = npool; if (nnew > nnewmax) nnewmax = nnew; if (condwords > ncondmax) ncondmax = condwords; ! return [super createEnd]; } *************** *** 314,320 **** bfParams->maxdev = maxdev; bfParams->poolfrac = poolfrac; bfParams->newfrac = newfrac; ! bfParams->pcrossover = pcrossover; bfParams->plinear = plinear; bfParams->prandom = prandom; bfParams->pmutation = pmutation; --- 296,304 ---- bfParams->maxdev = maxdev; bfParams->poolfrac = poolfrac; bfParams->newfrac = newfrac; ! bfParams->pcrossover = pcrossover; ! bfParams->psocial = psocial; ! bfParams->startsocial = startsocial; bfParams->plinear = plinear; bfParams->prandom = prandom; bfParams->pmutation = pmutation; *************** *** 336,341 **** --- 320,342 ---- } + + - (void)lispOutDeep: stream + { + [stream catStartMakeInstance: "BFParams"]; + [super lispOutVars: stream deep: YES];//Important to note this!! + + [super lispStoreIntegerArray: bitlist Keyword: "bitlist" Rank: 1 Dims: &condbits Stream: stream]; + + [super lispStoreDoubleArray: problist Keyword: "problist" Rank: 1 Dims: &condbits Stream: stream]; + + [stream catEndMakeInstance]; + } + + + + + @end diff -rc ASM-2.2.1/BitVector.h ASM-2.4/BitVector.h *** ASM-2.2.1/BitVector.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/BitVector.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 8,20 **** } ! - createEnd; + init; - (void)setCondwords: (int)x; ! - (void) setCondbits: (int)x; - (void)setConditions: (int *)x; --- 8,20 ---- } ! - init; + init; - (void)setCondwords: (int)x; ! - (void)setCondbits: (int)x; - (void)setConditions: (int *)x; *************** *** 40,43 **** --- 40,45 ---- - printcond: (int)word; + - (void)lispOutDeep: stream; + @end diff -rc ASM-2.2.1/BitVector.m ASM-2.4/BitVector.m *** ASM-2.2.1/BitVector.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/BitVector.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 1,6 **** #import "BitVector.h" #import //for limits.h in print method - //needed for bit math. same as in BFAgent was. #define WORD(bit) (bit>>4) --- 1,5 ---- *************** *** 100,109 **** /*"Allocate dynamic memory to hold the bit vector. There are "condwords"*sizeof(unsigned int) words of memory allocated."*/ ! - createEnd { int i; ! if (!condwords ){fprintf(stderr,"Must have condwords to create BFCast."); exit(1);} conditions=[[self getZone] allocBlock: condwords*sizeof(unsigned int)]; for(i=0;i + + * BFagent.h: created new ivar medianstrength for use in fMoments, + local variable in GA and fMoments still called medstrength. + + * BFagent.m: changed bitDistribution to count only bits of + forecast that were used within the last 10000 periods. changed + fMoments to calculate means and absolute mean deviations of + forecast parameters and forecast variance. + + * BFCast.m ([BFCast -createEnd]): introduced new ivar lastused to + track last actual use of forecast in contrast to lastactive, that + tracks when forecast was last in activelist. + + 2003-06-07 Paul E. Johnson + + * Output.h (SwarmObject): seems to me bs[] array only should have 12 + items if BFParams only lists 12 conditions being monitored. This + whole setup is horribly hard wired to the particular 12 bits + described in BFParams. + + * Dividend.m ([Dividend -initNormal]): subtract 5 from system seed + rather than add to get seed. + + 2003-06-06 Paul E. Johnson + + * BFagent.m ([BFagent -getNfcasts]): retrieve the number + of forecasts that is in use. Primarily for use in Output.m + + 2003-06-06 Thomas Badegruber + + * asm.scm (cons): changed values to mirror original publication + + * Output.m ([Output -createTimePlots]): changed createTimePlots + and calculateBitData to correctly count and plot averages of the + now 12 information bits grouped in technical, fundamental, dummy + and overall bits. + + * Dividend.m (normal) new function that returns a normally + distributed random variable. copied from original version to see + if algorithm leads to changes in results. function is currently + not in use. + + * BFagent.m: removed variable minstrength. increased currentTime + by one to fix discrepancy between counting of of modeltime, + lastused and count. selection of rules is now based on minimum + actual variance (actvar), but demand function still uses + variance. see lebaron (1999) for reasons. + ([BFagent -updatePerformance]): variance reset to initial value as + long as currentTime < tauv. moving average calculation for actvar + begins at time 1. + ([BFagent -performGA]): changed some methods inside GA to + calculate and deal with median strength. fixed very bad error in + sorting algorithm in MakePool. changed selection of candidates in + Tournament. included actvar and removed the assignment of a new + strength value in CopyRule. in Mutate, the value of bool variable + changed is only set to YES if the range of the variable (a,b, or + c) != 0. mutations of b, which is usually set to 0 do not cause + changed to be set to YES. unused rules or rules that have not been + matched for a long time get median strength in Mutate + method. count value of mutated rules is not reset to 0. In + Crossover, lastactive of new rule is calculated as average of its + parents, count is set to the smaller value of both parents, + strength is set to median strength if rule has not been used at + all or for a long time.GetMort now includes all three methods for + selecting rules to leave, although GetMort is not used as long as + newlist and rejectlist are of the same size. In Generalize, + varvalue is replaced by actvar to calculate a variance backwards + out of median strength. + + * BFagent.h: changed variable names from avgstrength to + medstrength since BFagent now uses median strength instead of + average strength. + + * BFParams.m ([BFParams -init]): reduced the set of information + bits to fit original publications. + + * BFCast.m ([BFCast -updateSpecfactor]): changed calculation of + specfactor, since condbits is already adjusted for + nnulls. implemeneted get and set method for actvar and included it + in copyEverthingFrom. + + * BFCast.h (SwarmObject): added new ivar actvar to hold actual + variance, the current variance estimate of a forecast. forecast + variance itself is only updated during GA. introduced get and set + method for actvar. + + * ASMModelSwarm.m ([ASMModelSwarm -buildActions]): changed the + number of warmup runs to 501 from 502, deleted additional + periodActions at time 0 to fix discrepancy between the counting of + modeltime, lastused and count in BFagent. + + 2003-05-18 Paul E. Johnson + + * Output.m ([Output -calculateBitData]): csfreq is new ivar to + remember important values that are graphed. + + * BFParams.m: delete getDouble because of memory leak. + + * ASMBatchSwarm.m ([ASMBatchSwarm -buildActions]): output updates + to suit graph usage changes in Output + + * Output.m ([Output -createEnd]): simplified data storage options. + Now only save time streams as C fprintf text and HDF vectors + through graphs. + + 2003-05-17 Paul E. Johnson + + * Output.m ([Output -calculateBitData]): new method, separated + from writeData method + ([Output -getCS:i]): new method to give cs data for plotting + + * ASMObserverSwarm.m ([ASMObserverSwarm -buildObjects]): moved + graphs of price and volume int Output.m. + ([ASMObserverSwarm -_writeRawData_]): deleted. Not needed due to + redesign. + + 2003-05-16 Paul E. Johnson + + * BFagent.h (Agent): remove lastgatime and avgspecificity. + + Have to declare all these methods in order for them to be inherited. + + - (BFCast *) CopyRule:(BFCast *) to From: (BFCast *) from; + - (void) MakePool: (id )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; + - (BFCast *) Tournament: (id ) list; + - (double) CalculateAndUseMadv; + - (double) CalculateAvAndMinstrength; + - (BFCast *) CreateFcastAvstrength: (double)avstrength Madv: (double)madv; + - (BOOL) PickParents: (BFCast *) aNewForecast; + + * BFagent.m ([BFagent -CalculateAvAndMinstrength]): new method to clean up GA. + ([BFagent -CalculateAndUseMadv]): new method to clean up GA. + ([ -CalculateAvAndMinstrength]): new method to clean up GA. + ([BFagent -CreateFcastAvstrength:Madv:]): new method to clean up GA. + + 2003-03-26 Paul E. Johnson + + * BFagent.m: close memory leak in prepareForTrading. Was caused + by getDouble() function, which had called a probeAsDouble. + + * ASMModelSwarm.m ([ASMModelSwarm -buildObjects]): remember + randomSeed all the time, whether we put it in or not. + + 2003-03-27 Paul E Johnson + + * ASMObserverSwarm.m ([ASMObserverSwarm -buildObjects]): Thomas + Badegruber pointed out ASM crashes on windows systems and + submitted a patch. + + 2003-03-27 Paul E. Johnson + + * World.m (changes): Rewrite all MA code to access Swarm + Arrays, not C arrays. This is for serialization. + (NWORLDBITS): Stop calculating NWORLDBITS, just declare + a number in World.h. This allows the realworld array to be + statically allocated. + + * World.h (SwarmObject): convert priceMA, oldpriceMA and divMA and + olddivMA into Swarm Arrays for serialization. + + * World.m (changes): Serialization: eliminate dynamic memory + allocation of + + * BFagent.m ([BFagent -collectWorldData:]): init for BitVector + need. Serialzation was the reason. + + * BFCast.m ([BFCast -init]): must call init in BitVector every + time a BitVector is created. + + + * BitVector.h: changed createEnd to init method, for serialization. + + * ASMModelSwarm.m ([ASMModelSwarm -lispLoadAgents:]): new method + to restore agents from the saved scm file + ([ASMModelSwarm -createAgents]): separate method to create + agents. Used only if an input scm file is not present. + + * BFCast.m ([BFCast -init]): new method to initialize the BFCast. + Same work used to be done in createEnd, but serialization conflicts + with that usage. + + * BFagent.m ([BFagent -createNewForecast]): call init method when + BFCast is created. needed for serialization. + + 2003-03-27 + + * SOCagent.m ([SOCagent -PickParents:]): introduced first type of + social behaviour: look at strongest forecast of agent at offset 0 + and copy it. + + 2003-03-27 Thomas Badegruber + + * BFagent.m ([BFagent -updateActiveList:]): introduced + strongestBFCast as instance variable for use in + SOCagent. SOCagents are able to ask each other for strongest + forecast. also created get-method for strongestBFCast + + * BFParams.h: added psocial and startsocial to list of parameters + that can be read out of asm.scm. corresponding changes also in + BFParams.m and asm.scm. + + * ASMModelSwarm.m deleted comments and examples of previous + versions + + * World.m: also deleted comments. + + * Dividend.m ([Dividend -initNormal]): also deleted comments. + + * BFCast.m: also deleted comments. + + * ASMBatchSwarm.m ([ASMBatchSwarm +createBegin:]): deleted + legacies of older versions that were already commented out. + + * BFagent.m ([BFagent -performGA]): removed lastgatime variable, + because it is of no use + + * ASMObserverSwarm.m ([ASMObserverSwarm -buildObjects]): inserted + "if ([controlPanel getState] == ControlStateQuit) return self;" to + fix troubles when pressing Quit on controlpanel. fixed error in + enableDestroyNotification for volumeGraph + ([ASMObserverSwarm -drop]): inserted + [priceGraph drop]; + [volumeGraph drop]; + [positionHisto drop]; + [relativeWealthHisto drop]; to fix trouble at shutdown in Windows + + * BFagent.m: got rid of all unneccessary comments and explanations + of previous versions of the market in BFagent.m, eliminated + WEIGHTED == 1 part, since it did not work. deleted alternative + implementation to create activelist. removed empty methods that + were designed for ANNagents. gotten rid of av, bv ignoring BLs + comment in updatePerformance, used a, b that are based on tauv + instead. usefulnes of global_mean seriously in doubt since it is + only used at start when new forecasts are created. removed + lastgatime variable and method because its of no use + + + 2003-03-26 Paul E. Johnson + + * ASMModelSwarm.m ([ASMModelSwarm -buildObjects]): remember + randomSeed in asmModelParams. This means if a randomSeed is not + entered by the user, the one chosen by Swarm will be recorded. + + * asmModelParamsrandomSeed variable will equal the GUI input, + otherwise it will equal the value used by the default or the CLI. + + * BFagent.m ([BFagent -MakePool:From:]): fix bug where only + npool-1 rules were created. iterate from 1 to n, not 1 to n-1. + + 2003-03-26 Thomas Badegruber + + * ASMModelParams.m ([ASMModelParams +createBegin:aZone]): removed + tauv, lambda and initvar from asm.scm and the probemap in + ASMModelParams.m because they are not needed, since pj introduced + the BFParams + + * BFagent.m ([BFagent -prepareForTrading]) fixed the memory leak + at the very end of the method. it now says + divisor=privateParams->lambda*forecastvar; instead of + divisor =getDouble(privateParams,"lambda")*forecastvar; + + + 2003-03-25 Paul E. Johnson + + * ASMObserverSwarm.m ([ASMObserverSwarm + -_relativeWealthHistoDeath_:]): windows users say Swarm crashes on + shutdown. + + >>>>>>> 1.28.2.10 + 2003-03-18 Paul E Johnson + + * BFagent.m ([BFagent -updateActiveList:]): Looking for speedups in + calculations after gcc profiling pointed at this as a slow down. Done + by saving values of real world once for each batch of forecasts and only + making one "getConditions" call on each forecast. + + int * real = [worldvalues getConditions]; + index=[ fcastList begin: [self getZone]]; + for ( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) + { + int * conditions = [aForecast getConditions]; + if ( conditions[0] & real[0] ) continue ; + if ( conditions[1] & real[1] ) continue ; + if ( conditions[2] & real[2] ) continue ; + [activeList addLast: aForecast]; + } + [index drop]; + + * ASMModelSwarm.m ([ASMModelSwarm -buildActions]): explore variations to + make model run faster. Stop using createActionForEach. Consider 2 alternatives, + both equally fast. See comments. + + 2003-03-11 Paul E Johnson + + * World.m ([World +nameOfBit:]): NUMWORLDBITS is an unsigned, have + to cast as (int) in order to do comparisons. Necessitated by + gcc-3.3 + + * BFagent.m ([BFagent -performGA]): Thomas Badegruber pointed out + typos on lines 1199 1455. He says they don't affect results. + 2002-10-02 Paul E Johnson * World.m (bitnamelist): Put parens around GETMA macro. Thanks to diff -rc ASM-2.2.1/Dividend.h ASM-2.4/Dividend.h *** ASM-2.2.1/Dividend.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/Dividend.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 16,22 **** // Measured in units of "baseline". The standard // deviation of the process is proportional to this."*/ ! int period; /*"The period or auto-correlation time of the process."*/ double mindividend; /*"floor under dividend values"*/ double maxdividend; /*"ceiling for dividend values"*/ --- 16,22 ---- // Measured in units of "baseline". The standard // deviation of the process is proportional to this."*/ ! double period; /*"The period or auto-correlation time of the process."*/ double mindividend; /*"floor under dividend values"*/ double maxdividend; /*"ceiling for dividend values"*/ *************** *** 38,43 **** --- 38,44 ---- - setDerivedParams; - (double)dividend; + - (double) normal; @end diff -rc ASM-2.2.1/Dividend.m ASM-2.4/Dividend.m *** ASM-2.2.1/Dividend.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/Dividend.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 5,15 **** #import "Dividend.h" - //#import "random.h" #import //swarm library to get NormalDist #include #include @implementation Dividend --- 5,17 ---- #import "Dividend.h" #import //swarm library to get NormalDist #include #include + extern long random(void); + static int set = 0; + static double gset; @implementation Dividend *************** *** 23,48 **** - initNormal { ! normal=[NormalDist create: [self getZone] setGenerator: randomGenerator setMean: 0 setVariance: 1]; return self; } ! -setBaseline: (double)theBaseline { baseline = theBaseline; return self; } ! -setmindividend: (double)minimumDividend { mindividend = minimumDividend; return self; } ! -setmaxdividend: (double)maximumDividend { maxdividend = maximumDividend; return self; --- 25,53 ---- - initNormal { ! //id myMTgen = [PMMLCG1gen create: [self getZone] setStateFromSeed: [randomGenerator getInitialSeed] + 5]; ! id myMTgen = [MT19937gen create: [self getZone] setStateFromSeed: [randomGenerator getInitialSeed] + 5]; ! ! normal = [NormalDist create: [self getZone] setGenerator: myMTgen setMean: 0 setVariance: 1]; return self; } ! - setBaseline: (double)theBaseline { baseline = theBaseline; return self; } ! - setmindividend: (double)minimumDividend { mindividend = minimumDividend; return self; } ! - setmaxdividend: (double)maximumDividend { maxdividend = maximumDividend; return self; *************** *** 53,59 **** // value actually set, which may be clipped or rounded compared to the // supplied argument. See "-setDivType:". "*/ ! -(double)setAmplitude:(double)theAmplitude { amplitude = theAmplitude; if (amplitude < 0.0) --- 58,64 ---- // value actually set, which may be clipped or rounded compared to the // supplied argument. See "-setDivType:". "*/ ! - (double)setAmplitude:(double)theAmplitude { amplitude = theAmplitude; if (amplitude < 0.0) *************** *** 68,74 **** // value actually set, which may be clipped compared to the supplied // argument. See "-setDivType:". "*/ ! -(int)setPeriod: (int)thePeriod { period = thePeriod; if (period < 2) --- 73,79 ---- // value actually set, which may be clipped compared to the supplied // argument. See "-setDivType:". "*/ ! - (int)setPeriod: (int)thePeriod { period = thePeriod; if (period < 2) *************** *** 77,83 **** } ! -setDerivedParams /* * Sets various parameters derived from the externally-settable ones. This * is called lazily, when a parameter is needed and the needsSetDerivedParams --- 82,88 ---- } ! - setDerivedParams /* * Sets various parameters derived from the externally-settable ones. This * is called lazily, when a parameter is needed and the needsSetDerivedParams *************** *** 89,97 **** rho = exp(-1.0/((double)period)); rho = 0.0001*rint(10000.0*rho); gauss = deviation*sqrt(1.0-rho*rho); - //pj: - //dvdnd = baseline + gauss*normal(); dvdnd = baseline + gauss*[normal getDoubleSample]; return self; } --- 94,101 ---- rho = exp(-1.0/((double)period)); rho = 0.0001*rint(10000.0*rho); gauss = deviation*sqrt(1.0-rho*rho); dvdnd = baseline + gauss*[normal getDoubleSample]; + //dvdnd = baseline + gauss*[self normal];; return self; } *************** *** 102,123 **** variable "t" because shifts are introduced to maintain phase when certain parameters are changed."*/ ! -(double)dividend { ! //pj: ! // dvdnd = baseline + rho*(dvdnd - baseline) + gauss*normal(); ! dvdnd = baseline + rho*(dvdnd - baseline) + gauss*[normal getDoubleSample]; if (dvdnd < mindividend) dvdnd = mindividend; if (dvdnd > maxdividend) dvdnd = maxdividend; - // printf(" \n \n World dividend %f baseline %f rho %f max %f min %f\n \n", dvdnd, baseline, rho, maxdividend, mindividend); - return dvdnd; } @end --- 106,159 ---- variable "t" because shifts are introduced to maintain phase when certain parameters are changed."*/ ! - (double)dividend { ! dvdnd = baseline + rho*(dvdnd - baseline) + gauss*[normal getDoubleSample]; ! //dvdnd = baseline + rho*(dvdnd - baseline) + gauss*[self normal]; if (dvdnd < mindividend) dvdnd = mindividend; if (dvdnd > maxdividend) dvdnd = maxdividend; return dvdnd; } + /*------------------------------------------------------*/ + /* normal */ + /*------------------------------------------------------*/ + - (double) normal + /* + * function normal - returns random variable n(0,1), was used in original version, may be used for comparison + * + * This function converts uniform random numbers to normal + * random numbers. The algorithm comes out of numerical + * recipes. Note that it may return slightly different values depending + * on whether it is compiled with optimization, since floating point + * registers have more precision than stored double's on some machines + * (including m68k). + */ + { + double v1, v2, fac, r; + if (set) { + set = 0; + return gset; + } + else { + do { + v1 = [uniformDblRand getDoubleWithMin: -1 withMax: 1]; + v2 = [uniformDblRand getDoubleWithMin: -1 withMax: 1]; + r = v1*v1 + v2*v2; + } while (r >= 1.0); + fac = sqrt(-2.0*log(r)/r); + gset = v2*fac; + set = 1; + return v1*fac; + } + } + + + @end Only in ASM-2.4: .libs diff -rc ASM-2.2.1/main.m ASM-2.4/main.m *** ASM-2.2.1/main.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/main.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 40,46 **** if (swarmGUIMode == 0) [theTopLevelSwarm expostParamWrite]; [theTopLevelSwarm drop]; - //if ( [[theTopLevelSwarm getControlPanel] setStateQuit] ) break; } // The toplevel swarm has finished processing, so it's time to quit. return 0; --- 40,45 ---- diff -rc ASM-2.2.1/Makefile ASM-2.4/Makefile *** ASM-2.2.1/Makefile 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/Makefile 2003-06-21 12:33:21.000000000 -0500 *************** *** 16,28 **** main.o: main.m ASMObserverSwarm.h ASMBatchSwarm.h Agent.o: Agent.h Agent.m ! BFAgent.o: BFagent.h BFagent.m BFParams.h BFCast.h World.h BitVector.h Dividend.o: Dividend.h Dividend.m Output.o: Output.h Output.m BFParams.h ASMModelParams.h ASMModelSwarm.o: ASMModelSwarm.h ASMModelSwarm.m BFParams.o Specialist.o: Specialist.h Specialist.m World.o: World.h World.m MovingAverage.h ! ASMModelSwarm.o: ASMModelSwarm.h ASMModelSwarm.m Output.h BFParams.h Specialist.h Dividend.h World.h BFagent.h Agent.h ASMObserverSwarm.o: ASMObserverSwarm.h ASMObserverSwarm.m ASMBatchSwarm.o: ASMBatchSwarm.h ASMBatchSwarm.m BFParams.o: BFParams.h BFParams.m World.h --- 16,28 ---- main.o: main.m ASMObserverSwarm.h ASMBatchSwarm.h Agent.o: Agent.h Agent.m ! BFagent.o: BFagent.h BFagent.m BFParams.h BFCast.h World.h BitVector.h Dividend.o: Dividend.h Dividend.m Output.o: Output.h Output.m BFParams.h ASMModelParams.h ASMModelSwarm.o: ASMModelSwarm.h ASMModelSwarm.m BFParams.o Specialist.o: Specialist.h Specialist.m World.o: World.h World.m MovingAverage.h ! ASMModelSwarm.o: ASMModelSwarm.h ASMModelSwarm.m Output.h BFParams.h Specialist.h Dividend.h World.h BFagent.h Agent.h BFagent.h ASMObserverSwarm.o: ASMObserverSwarm.h ASMObserverSwarm.m ASMBatchSwarm.o: ASMBatchSwarm.h ASMBatchSwarm.m BFParams.o: BFParams.h BFParams.m World.h *************** *** 31,34 **** ASMModelParams.o: ASMModelParams.h ASMModelParams.m Parameters.o: Parameters.h Parameters.m ASMModelParams.h BFParams.h MovingAverage.o: MovingAverage.h MovingAverage.m - --- 31,33 ---- diff -rc ASM-2.2.1/MovingAverage.h ASM-2.4/MovingAverage.h *** ASM-2.2.1/MovingAverage.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/MovingAverage.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 32,37 **** --- 32,40 ---- - (void)drop; + + - (void)lispOutDeep: stream; + @end diff -rc ASM-2.2.1/MovingAverage.m ASM-2.4/MovingAverage.m *** ASM-2.2.1/MovingAverage.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/MovingAverage.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 67,73 **** { movingAverage = (double)sumOfInputs / (double) width; } ! //printf( "Object: ma=%f sumOfInput: %f numInputs: %d \n",movingAverage, sumOfInputs, numInputs); return movingAverage; } --- 67,73 ---- { movingAverage = (double)sumOfInputs / (double) width; } ! return movingAverage; } *************** *** 113,118 **** --- 113,132 ---- + + - (void)lispOutDeep: stream + { + [stream catStartMakeInstance: "MovingAverage"]; + [super lispOutVars: stream deep: YES];//Important to note this!! + + [super lispStoreDoubleArray: maInputs Keyword: "maInputs" Rank: 1 Dims: &width Stream: stream]; + + [stream catEndMakeInstance]; + } + + + + @end diff -rc ASM-2.2.1/Output.h ASM-2.4/Output.h *** ASM-2.2.1/Output.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/Output.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 18,57 **** World * outputWorld; /*"Reference to the world, where we can get data!"*/ Specialist * outputSpecialist; /*" Reference to the Specialist object, where we can get data!"*/ ! id archiver, dataArchiver; /*"hdf5 or LISP objects, depending on the CPP flags"*/ ! time_t runTime; /*"Return from the systems time() function"*/ char timeString[100];/*"a verbose description of current time"*/ FILE * dataOutputFile; /*"FILE handle for output from C style fprintf"*/ ! id hdfWriter; /*"EZGraph object that is used only to create hdf5 formatted output"*/ id hdf5container; /*"HDF5 data container object used by hdfWriter"*/ @public int currentTime; /*"current time of simulation"*/ - // These IVARs were previously used for record keeping, but they - // are not needed now. Could reinstate and add "self" to the - // objects that the archiver dumps out. - // double price; /*"current price"*/ - // double dividend; /*"current dividend"*/ - // double volume; /*"current volume"*/ } ! -setSpecialist: (Specialist *)theSpec; ! -setWorld: (World *)theWorld; - writeParams: modelParam BFAgent: bfParms Time: (long int) t; ! -prepareOutputFile; ! -(void) initializeHDFWriter; ! -writeData; ! -(void) drop; @end --- 18,80 ---- World * outputWorld; /*"Reference to the world, where we can get data!"*/ Specialist * outputSpecialist; /*" Reference to the Specialist object, where we can get data!"*/ ! id agentList; ! ! id archiver; /*"LISP archiver object"*/ ! ! int bs[12]; //*"counter array, size of number of bits in use"*/ ! double csfreq[4]; ! double moments[8]; ! time_t runTime; /*"Return from the systems time() function"*/ + time_t now; char timeString[100];/*"a verbose description of current time"*/ FILE * dataOutputFile; /*"FILE handle for output from C style fprintf"*/ ! id hdf5container; /*"HDF5 data container object used by hdfWriter"*/ + + id priceGraph; /*"Time plot of risk neutral and observed market price"*/ + + id volumeGraph; /*"Time plot of market trading volume"*/ + id bitGraph; /*"Time plot of risk neutral and observed market price"*/ + id volsequence; //sequences for data on volume + id prsequence[2]; //sequences for data price (observed and expected) + id cssequence[3]; + id bssequence[16]; + @public int currentTime; /*"current time of simulation"*/ } ! - setSpecialist: (Specialist *)theSpec; ! ! - setWorld: (World *)theWorld; ! ! - (void)setAgentlist: list; ! ! - _priceGraphDeath_ : caller; ! - _volumeGraphDeath_ : caller; - writeParams: modelParam BFAgent: bfParms Time: (long int) t; ! - prepareCOutputFile; ! ! - createTimePlots; ! ! - calculateBitData; ! ! - (double)getCSfreq: (unsigned) i; ! - stepPlots; ! - writeCData; ! - (void)drop; @end diff -rc ASM-2.2.1/Output.m ASM-2.4/Output.m *** ASM-2.2.1/Output.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/Output.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 1,38 **** #import "Output.h" #include // stdio, time ! ! /*" ! To show the possible data output tools, I have 3 ! different ways of saving the output time streams from the model. All ! three should be similar/equivalent representations of the numbers. 1) Text output of data streams. ! 2) HDF5 or LISP format output of object dumps from a "putShallow" ! call to a data archiver object. This dumps full snapshots of ! the world and the specialist into a LISP on hdf5 archive. ! 3) HDF5 output EZGraph which writes one vector per plotted line into an hdf5 file. ! This code has a preprocessor flag to control the behavior of data ! storage. If compile without any CPP flags, then the data files are ! saved in the .scm format, which is "scheme". Otherwise, use the flag ! NO_LISP, and it uses hdf5 format. In Swarm, that means you type the ! make command: ! ! make EXTRACPPFLAGS=-DNO_LISP ! ! ! The buttons in the ASMObserverSwarm display turn on data saving. Look ! for "writeSimulationParams" and the other "toggleDataWrite". These ! were in the original ASM Swarm model, but I've replaced the ! functionality with the newer storage methods. The data is saved only ! if you turn on the writeData option. If "toggleDataWrite" is empty or ! false, hit that button and it shows "true". When the model runs, ! output will be created. If you run the program in batch mode, it ! automatically turns on the data writing. Please note that if you want the simulation to save your parameter values to a file, you can click the GUI button --- 1,36 ---- #import "Output.h" #include // stdio, time ! #import "BFagent.h" ! #import "BFCast.h" //for bitDist ! #import ! #import "Parameters.h" /*" ! This class helps with data output. The time plots will ! show on the screen--if you want--and they also write data into files. ! ! The time stream data is saved in two formats, just for ! demonstration purposes. 1) Text output of data streams. ! 2) HDF5 output EZGraph which writes one vector per plotted line into an hdf5 file. ! The latter requires your system have HDF5 installed. If not, ! compile with this command: ! ! make EXTRACPPFLAGS=-DNO_HDF5 ! ! The hdf5 file is created EVERY TIME YOU RUN THE MODEL. ! ! The text ouput file will be created only if you turn it on from the ! graphical interface or you run the model in batch model. The buttons ! in the ASMObserverSwarm display turn on data saving in text format. ! Look for "toggleDataWrite". If "toggleDataWrite" is empty or false, ! hit that button and it shows "true". When the model runs, output will ! be created. If you run the program in batch mode, it automatically ! turns on the data writing. Please note that if you want the simulation to save your parameter values to a file, you can click the GUI button *************** *** 42,49 **** guiSettingsThu_Jun_28_23_48_00_2001.scm ! if you did not compile with the NO_LISP flag. Otherwise you get a ! .hdf file. One key change from the old ASM is that you can push that button at time 0, and it will save a snap at that time, and any time you stop the model, you can change parameters and punch the button again, and it will also save a snapshot at quit time. I believe this --- 40,46 ---- guiSettingsThu_Jun_28_23_48_00_2001.scm ! One key change from the old ASM is that you can push that button at time 0, and it will save a snap at that time, and any time you stop the model, you can change parameters and punch the button again, and it will also save a snapshot at quit time. I believe this *************** *** 59,84 **** output.data_Thu_Jun_28_23_48_00_2001 - However, I understand the reasons others are pushing to use more ! refined formats. Many people are digging into hdf5 format for data ! storage, and I've taken a look at that too. I took the easy road and ! just dumped the whole world and specialist class with swarm's ! archiver. It seems to work great?! The output file is called ! something like ! ! swarmDataArchiveFri_Jun_29_16_29_25_2001.hdf ! or ! swarmDataArchiveFri_Jun_29_16_22_59_2001.scm ! ! You note here that output uses the current time and date to write the ! output file names. Today I ran an example and ended up with these ! three files of output: ! ! output.dataWed_Oct_24_11_30_18_2001 ! swarmDataArchiveWed_Oct_24_11_30_18_2001.scm ! hdfGraphWed_Oct_24_11_30_18_2001.hdf "*/ @implementation Output --- 56,78 ---- output.data_Thu_Jun_28_23_48_00_2001 However, I understand the reasons others are pushing to use more ! refined formats. So I've used the Swarm EZGraph for the dual purposes ! of drawing on the screen and writing into an hdf5 file. The hdf5 file ! has the run number appended to the basename of the file, so, for example, ! the output of run 33 would be named: ! ! stockData33.hdf ! ! If you are running from the graphical interface and the run variable ! is not explicitly set, then run equals "-1" and the output file will ! have a date string pasted into it: ! ! stockData-Sun_May_18_10_47_58_2003.hdf ! ! "*/ + @implementation Output *************** *** 93,102 **** char paramFileName[100]; - char dataArchiveName[100]; - if(!runTime) runTime = time(NULL); dataFileExists = NO; strcpy (timeString, ctime(&runTime)); --- 87,95 ---- char paramFileName[100]; if(!runTime) runTime = time(NULL); + dataFileExists = NO; strcpy (timeString, ctime(&runTime)); *************** *** 117,147 **** strcpy (paramFileName,"batchSettings"); strcat (paramFileName, timeString); - - - strcpy (dataArchiveName,"swarmDataArchive"); - strcat (dataArchiveName, timeString); - #ifdef NO_LISP - strcat (paramFileName,".hdf"); - strcat (dataArchiveName,".hdf"); - #else strcat (paramFileName,".scm"); ! strcat (dataArchiveName,".scm"); ! #endif ! ! #ifdef NO_LISP ! archiver = [HDF5Archiver create: [self getZone] setPath: paramFileName]; ! dataArchiver = [HDF5Archiver create: [self getZone] setPath: dataArchiveName]; ! #else ! //unlink ("settingsSaved.scm"); archiver = [LispArchiver create: [self getZone] setPath: paramFileName]; ! //unlink ("settingsSaved.scm"); ! dataArchiver = [LispArchiver create: [self getZone] setPath: dataArchiveName]; ! #endif ! ! return self; } --- 110,126 ---- strcpy (paramFileName,"batchSettings"); strcat (paramFileName, timeString); strcat (paramFileName,".scm"); ! ! unlink ("settingsSaved.scm"); ! archiver = [LispArchiver create: [self getZone] setPath: paramFileName]; ! unlink ("settingsSaved.scm"); ! for (i=0; i<12; i++) bs[i]=0; ! for (i=0; i<4; i++) csfreq[i]=0; ! for (i=0; i<8; i++) moments[i]=0; return self; } *************** *** 159,184 **** return self; } /*"This flushes a snapshot of the current parameter settings from both the ASMModelParams and BFAgentParams into a file"*/ - writeParams: modelParam BFAgent: bfParms Time: (long int) t { char modelKey[20]; char paramKey[20]; - sprintf (modelKey, "modelParams%ld",t); sprintf (paramKey, "bfParams%ld",t); [archiver putShallow: modelKey object: modelParam]; - #ifndef NO_LISP [archiver sync]; - #endif [archiver putShallow: paramKey object: bfParms]; - #ifndef NO_LISP [archiver sync]; ! #endif return self; } --- 138,166 ---- return self; } + + - (void)setAgentlist: list + { + agentList = list; + } + + /*"This flushes a snapshot of the current parameter settings from both the ASMModelParams and BFAgentParams into a file"*/ - writeParams: modelParam BFAgent: bfParms Time: (long int) t { char modelKey[20]; char paramKey[20]; sprintf (modelKey, "modelParams%ld",t); sprintf (paramKey, "bfParams%ld",t); [archiver putShallow: modelKey object: modelParam]; [archiver sync]; [archiver putShallow: paramKey object: bfParms]; [archiver sync]; ! return self; } *************** *** 189,195 **** initialize the data output files. Each time this is called, it checks to see if the files have already been initialized. That way it does not initialize everything twice."*/ ! - prepareOutputFile { char outputFile[256]; --- 171,177 ---- initialize the data output files. Each time this is called, it checks to see if the files have already been initialized. That way it does not initialize everything twice."*/ ! - prepareCOutputFile { char outputFile[256]; *************** *** 202,311 **** if(!(dataOutputFile = fopen(outputFile,"w"))) abort(); ! fprintf (dataOutputFile, "currentTime\t price\t\t dividend\t volume\n\n"); dataFileExists = YES; } return self; } - /*"In case the Output class is told to write output data and there is - no hdfWriter object yet, then this method will be run. I could not - find another way to make sure that this object was not created unless - the system actually tries to write data. It cannot be done in the - prepareOutputFile method, because that method can be called from the - GUI before the Specialist and World objects exist. Those objects are - necessary to initialize an hdfWriter, as seen in this code. "*/ ! -(void) initializeHDFWriter { char hdfEZGraphName[100]; - strcpy (hdfEZGraphName,"hdfGraph"); - strcat (hdfEZGraphName, timeString); - strcat (hdfEZGraphName, ".hdf"); hdf5container = [HDF5 createBegin: [self getZone]]; [hdf5container setWriteFlag: YES]; [hdf5container setName: hdfEZGraphName]; hdf5container = [hdf5container createEnd]; ! ! hdfWriter = [EZGraph create: [self getZone] ! setHDF5Container: hdf5container ! setPrefix: "market"]; ! [hdfWriter createSequence: "volume" ! withFeedFrom: outputSpecialist ! andSelector: M(getVolume)]; ! [hdfWriter createSequence: "price" ! withFeedFrom: outputWorld ! andSelector: M(getPrice)]; ! [hdfWriter createSequence: "dividend" ! withFeedFrom: outputWorld ! andSelector: M(getDividend)]; } ! /*"The write data method dumps out measures of the price, dividend, and volume indicators into several formats"*/ ! -writeData { long t = getCurrentTime(); ! char worldName[50]; ! char specName[50]; - //**** I've got 3 ways to write out numerical results. *****// - //**** Choose what you like ****// // First, just dump out the raw numbers in text. // This is the old standby! ! ! fprintf (dataOutputFile, "%10ld\t %5f\t %8f\t %f\n", t, [outputWorld getPrice], ! [outputWorld getDividend], [outputSpecialist getVolume]); ! // Second, dump those same values out to an hdf5 format file. This ! // uses the Archiver library "put shallow" to dump all primitive ! // types, ints and doubles mainly. ! ! sprintf (worldName, "world%ld",t); ! sprintf (specName, "specialist%ld",t); ! ! #ifndef NO_LISP ! [dataArchiver putShallow: worldName object: outputWorld]; ! [dataArchiver sync]; ! #else ! [dataArchiver putDeep: worldName object: outputWorld]; ! #endif ! ! [dataArchiver putShallow: specName object: outputSpecialist]; ! #ifndef NO_LISP ! [archiver sync]; ! #endif ! // Third, now use the EZGraph dump of its time strings. ! if (!hdfWriter) [self initializeHDFWriter]; ! [hdfWriter step]; ! ! return self; } /*"It is necessary to drop the data writing objects in order to make sure they finish their work. "*/ -(void) drop { if (dataOutputFile) fclose(dataOutputFile); - if (hdfWriter) [hdfWriter drop]; [archiver drop]; ! [dataArchiver drop]; [super drop]; } --- 184,474 ---- if(!(dataOutputFile = fopen(outputFile,"w"))) abort(); ! fprintf (dataOutputFile, "currentTime\t price\t\t riskfree price\t volume\n\n"); dataFileExists = YES; } return self; } ! ! /*"This method is needed to stop run-time hangs when users close graph windows by clicking on their system's window close button"*/ ! - _priceGraphDeath_ : caller ! { ! [priceGraph drop]; ! priceGraph = nil; ! return self; ! } ! ! /*"This method is needed to stop run-time hangs when users close graph windows by clicking on their system's window close button"*/ ! - _volumeGraphDeath_ : caller ! { ! [volumeGraph drop]; ! volumeGraph = nil; ! return self; ! } ! ! ! /*"This method is needed to stop run-time hangs when users close graph windows by clicking on their system's window close button"*/ ! - _bitGraphDeath_ : caller ! { ! [bitGraph drop]; ! bitGraph = nil; ! return self; ! } ! ! - createTimePlots { + int i = 0; + #ifndef NO_HDF5 + int run = [(Parameters *)arguments getRunArg]; char hdfEZGraphName[100]; + if (run != -1) + sprintf (hdfEZGraphName, "stockData-%d.hdf", run); + else + sprintf (hdfEZGraphName, "stockData-%s.hdf", timeString); hdf5container = [HDF5 createBegin: [self getZone]]; [hdf5container setWriteFlag: YES]; [hdf5container setName: hdfEZGraphName]; hdf5container = [hdf5container createEnd]; ! #endif ! ! priceGraph = [EZGraph createBegin: [self getZone]]; ! #ifndef NO_HDF5 ! [priceGraph setHDF5Container: hdf5container]; ! #endif ! [priceGraph setTitle: "Price v. time"]; ! [priceGraph setAxisLabelsX: "time" Y: "price"]; ! [priceGraph setWindowGeometryRecordName: "priceGraph"]; ! [priceGraph enableDestroyNotification: self ! notificationMethod: @selector (_priceGraphDeath_:)]; + if (swarmGUIMode == YES) + [priceGraph setGraphics: YES]; + else + [priceGraph setGraphics: NO]; ! priceGraph = [priceGraph createEnd]; ! #ifndef NO_HDF5 ! [priceGraph setFileOutput: YES]; ! [priceGraph setFileName: "prices"]; //name inside hdf5 file ! #endif ! ! prsequence[0] = [priceGraph createSequence: "actual price" ! withFeedFrom: outputWorld ! andSelector: M(getPrice)]; ! prsequence[1] = [priceGraph createSequence: "risk neutral price" ! withFeedFrom: outputWorld ! andSelector: M(getRiskNeutral)]; ! ! ! ! volumeGraph = [EZGraph createBegin: [self getZone]]; ! #ifndef NO_HDF5 ! [volumeGraph setHDF5Container: hdf5container]; ! #endif ! [volumeGraph setTitle: "Volume v. time"]; ! [volumeGraph setAxisLabelsX: "time" Y: "volume"]; ! [volumeGraph setWindowGeometryRecordName: "volumeGraph"]; ! if (swarmGUIMode == YES) ! [volumeGraph setGraphics: YES]; ! else ! [volumeGraph setGraphics: NO]; ! ! ! volumeGraph = [volumeGraph createEnd]; ! #ifndef NO_HDF5 ! [volumeGraph setFileOutput: YES]; ! [volumeGraph setFileName: "volume"]; //name inside hdf5 file ! #endif ! [volumeGraph enableDestroyNotification: self ! notificationMethod: @selector (_volumeGraphDeath_:)]; ! ! volsequence = [volumeGraph createSequence: "actual volume" ! withFeedFrom: outputSpecialist ! andSelector: M(getVolume)]; ! ! bitGraph = [EZGraph createBegin: [self getZone]]; ! #ifndef NO_HDF5 ! [bitGraph setHDF5Container: hdf5container]; ! #endif ! [bitGraph setTitle: "fraction of bits used (by type)"]; ! [bitGraph setAxisLabelsX: "time" Y: "frequency"]; ! [bitGraph setWindowGeometryRecordName: "bitGraph"]; ! if (swarmGUIMode == YES) ! [bitGraph setGraphics: YES]; ! else ! [bitGraph setGraphics: NO]; ! ! bitGraph = [bitGraph createEnd]; ! #ifndef NO_HDF5 ! [bitGraph setFileOutput: YES]; ! [bitGraph setFileName: "bituse"]; //name inside hdf5 file ! #endif ! [bitGraph enableDestroyNotification: self ! notificationMethod: @selector (_bitGraphDeath_:)]; ! ! for ( i = 0; i < 4; i++) ! { ! char name[10]; ! if (i == 0) sprintf (name, "fundamental bits"); ! else if (i == 1) sprintf (name, "technical bits"); ! else if (i == 2) sprintf (name, "dummy bits"); ! else if (i == 3) sprintf (name, "total bits"); ! ! cssequence[i] = [bitGraph createSequence: name ! withFeedFrom: self ! andSelector: M(getCSfreq:)]; ! [cssequence[i] setUnsignedArg: i]; ! } ! ! + return self; } ! ! - stepPlots { + [priceGraph step]; + [volumeGraph step]; + + [self calculateBitData]; + [bitGraph step]; + return self; + } + + + /*"This method gets bit usage information from agents and then + calculates how many bits are being used in each type--technical + or fundamental. This method assumes the bits are as coded in + BFParams.m, where 0-5 are fundamental, 6-9 are technical, + "*/ + - calculateBitData + { + int i; + static int *(*countpointer)[4]; + BOOL cum,first; + id index, agent; long t = getCurrentTime(); ! int condbits = 12; ! int cs[4]; ! int numagents = -1; ! int numFcasts = 0; ! ! cum = NO; ! first = YES; ! numagents = [agentList getCount]; ! countpointer = calloc(4,sizeof(int*)); ! ! for (i=0; i < condbits; i++) bs[i]=0; ! now = time(NULL); ! if (t%10000 == 0) printf("at time %s %7ld runs complete\n",asctime(localtime(&now)),t); ! ! //save for later calculation ! //assumes all agents use the same N of forecasts. ! //can easly generalize. ! ! numFcasts = [ [agentList atOffset:0] getNfcasts]; ! ! index = [agentList begin: [self getZone]]; ! while ((agent = [index next])) ! { ! [agent bitDistribution: countpointer cumulative:cum]; ! if (first) ! { ! [agent fMoments: moments cumulative:NO]; ! first = NO; ! } ! else ! [agent fMoments: moments cumulative:YES]; ! ! for (i = 0; i < [agent nbits];i++ ) ! { ! bs[i]=bs[i]+(*countpointer)[1][i]+(*countpointer)[2][i]; ! } ! } ! ! [index drop]; ! ! cs[0]=0; cs[1]=0; cs[2]=0; cs[3]=0; ! ! for (i = 0; i < condbits; i++) ! { ! if (i < 6) cs[0] = cs[0]+bs[i]; ! else if ( i >= 6 && i < 10) cs[1] = cs[1]+bs[i]; ! else cs[2] = cs[2]+bs[i]; ! cs[3] = cs[3]+bs[i]; ! } + //calculate the fraction of bits used among each type + + csfreq[0] = (double)cs[0]/(6.0*numagents*numFcasts); + csfreq[1] = (double)cs[1]/(4.0*numagents*numFcasts); + csfreq[2] = (double)cs[2]/(2.0*numagents*numFcasts); + csfreq[3] = (double)cs[3]/(condbits*numagents*numFcasts); + + for (i=0;i<8;i++) + moments[i] /= numagents; + + free (countpointer); + return self; + } + + - (double)getCSfreq: (unsigned) i + { + return csfreq[i]; + } + + + + //Modified by BaT 10.09.2002 to write additional agent-specific data on file*/ + + - writeCData + { + int i; + long t = getCurrentTime(); // First, just dump out the raw numbers in text. // This is the old standby! ! ! fprintf (dataOutputFile, "%10ld\t %5f\t %8f\t %f ", t, [outputWorld getPrice], ! [outputWorld getDividend]*10, [outputSpecialist getVolume]); ! ! for (i=0;i<12;i++) fprintf(dataOutputFile,"%3d ",bs[i]); ! fprintf(dataOutputFile,"%f %f %f %f ", csfreq[0], csfreq[1], csfreq[2], csfreq[3]); ! fprintf(dataOutputFile,"%f %f %f %f ",moments[0],moments[1],moments[6],moments[7]); ! fprintf(dataOutputFile,"\n"); ! ! return self; } + + /*"It is necessary to drop the data writing objects in order to make sure they finish their work. "*/ -(void) drop { + [priceGraph drop]; + [volumeGraph drop]; + if (dataOutputFile) fclose(dataOutputFile); [archiver drop]; ! [super drop]; } diff -rc ASM-2.2.1/Parameters.h ASM-2.4/Parameters.h *** ASM-2.2.1/Parameters.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/Parameters.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 9,14 **** --- 9,16 ---- ASMModelParams * asmModelParams; /*"parameter object used by ASMModelSwarm"*/ BFParams * bfParams;/*"parameter object used by BFagent and its various objects, such as BFCast "*/ int run; /*an integer indicating the run number of the current simulation. This is passed in as a command line parameter, as in --run=666 or such."*/ + char *filename; + } + createBegin: aZone; *************** *** 21,26 **** --- 23,31 ---- - init; + - (int) getRunArg; + + - (char *)getFilename; @end diff -rc ASM-2.2.1/Parameters.m ASM-2.4/Parameters.m *** ASM-2.2.1/Parameters.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/Parameters.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 27,39 **** + createBegin: aZone { static struct argp_option options[] = { ! {"run", 'R',"RunNumber",0,"Run is...",7}, { 0 } }; Parameters *obj = [super createBegin: aZone]; [obj addOptions: options]; return obj; } --- 27,44 ---- + createBegin: aZone { static struct argp_option options[] = { ! {"run", 'R',"RunNumber",0,"Run is...",6}, ! {"inputfile", 'I',"filename",0,"set fn",7}, { 0 } }; Parameters *obj = [super createBegin: aZone]; [obj addOptions: options]; + + obj->run=-1; + + obj->filename= NULL; return obj; } *************** *** 53,58 **** --- 58,68 ---- run = atoi(arg); return 0; } + else if (key == 'I') + { + filename = strdup(arg); + return 0; + } else return [super parseKey: key arg: arg]; *************** *** 64,78 **** then creating the parameter objects--asmModelParms and bfParams--that hold those values and make them avalable to the various objects in the model "*/ ! - init { ! if ((asmModelParams = ! [lispAppArchiver getWithZone: [self getZone] key: "asmModelParams"]) == nil) raiseEvent(InvalidOperation, ! "Can't find the modelSwarm parameters"); ! ! if ((bfParams = ! [lispAppArchiver getWithZone: [self getZone] key: "bfParams"]) == nil) raiseEvent(InvalidOperation, "Can't find the BFParam's parameters"); [bfParams init]; --- 74,103 ---- then creating the parameter objects--asmModelParms and bfParams--that hold those values and make them avalable to the various objects in the model "*/ ! - init ! { ! if (!filename) ! { ! asmModelParams = ! [lispAppArchiver getWithZone: [self getZone] key: "asmModelParams"]; ! bfParams = ! [lispAppArchiver getWithZone: [self getZone] key: "bfParams"]; ! ! } ! ! else ! { ! id archiver = [LispArchiver create: [self getZone] setPath: filename]; ! asmModelParams = [archiver getObject: "asmModelParams"]; ! bfParams = [archiver getObject: "bfParams"]; ! [archiver drop]; ! } ! if (asmModelParams == nil) raiseEvent(InvalidOperation, ! "Can't find the modelSwarm parameters"); ! ! if (bfParams == nil) raiseEvent(InvalidOperation, "Can't find the BFParam's parameters"); [bfParams init]; *************** *** 80,85 **** --- 105,115 ---- return self; } + + + + + /*"Returns an instance of ASMModelParams, the object which holds the model-level input parameters"*/ - (ASMModelParams*) getModelParams { *************** *** 113,118 **** --- 143,160 ---- } + + - (char *)getFilename + { + + if (filename) + return strdup(filename); + else + return NULL; + } + + + @end diff -rc ASM-2.2.1/README ASM-2.4/README *** ASM-2.2.1/README 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/README 2003-06-21 12:33:21.000000000 -0500 *************** *** 1,33 **** ! ASM-new. note from Paul Johnson April 2, 2000 ! SNAP1: May 7, 2000 ! In ASM-new-snap1, I've removed the random.h and random.m from this ! program, and replaced their functionality with Swarm library ! calls. Contrary to the statements below, this program should now ! behave like a Swarm app. Every time you run it, you get the same ! random seed, unless you use the command line switch or input a ! randomSeed of your own. ! SNAP2: ASM 20000602 June 2, 2000 ! Thorough workover of BFagent class, creating three new classes (BitVector, ! BFParams, and BFCast) and a massive reorganization of BFagent itself. ! See long comment in BFagent.m. SNAP3: ASM 20011024 October 2001 The aim has been to bring this model into convenient Swarm standards. ! Actually, the real aim has been to make ASM an effective teaching ! tool and an example of good simulation coding practice. ! Part of that is a modernization of the data handling, both the ! input of parameter values, and record keeping of parameter values, as ! well as the saving of data. One of my pet peeves about Swarm is that ! we do not have a standard, idiot proof way to keep records on the ! settings and results are for a particular run. We also don't have ! fool proof ways to interate models and run simulations over again. ! The first problem is dealt with here in the Output class, and the ! second one is dealt with by the creation of a Parameter class, where ! we could manage command line parameters if we wanted to. 1. Inputting Parameter Values. --- 1,95 ---- ! Swarm ASM notes. If you are looking for highlights, this ! is the right spot. ! Paul Johnson + ASM-2.4 June 2003 ! This version requires Swarm-2.1.143 or newer. If you don't have ! that, you will have to disable serialization features and compile ! without using HDF5 data output. ! ! Thomas Badegruber visited here in ! Kansas in March and then went to Boston to work with Blake ! LeBaron. That re-energized me on this project. Thomas is now a full ! contributor to the CVS archive on Sourceforge. We have made changes ! to improve functionality, fix bugs, and make the genetic algorithm ! code more easy to read and extend. And, perhaps most importantly, we ! can now re-produce the finding that there is a major difference in the ! usage of technical and fundamental bits when the agent use of the ! genetic algorithm is made more frequent. That is to say, when agents ! use the GA every 250 periods, they are substantially more likely to ! use technical trading information than if they update every 1000 ! periods. Because this behavior is now reproduced, we are confident ! that the Swarm-ASM behaves in the same way in all substantial ways as ! the Next/Objective-C models presented in the literature. ! ! Functionality enhancements ! ! * Graph showing usage of funamental bits, technical bits, and dummy ! bits full model serialization. ! ! * Serialization: Simulation can be saved in a "snapshot" and restarted. ! ! * Parameter values have been reset to match the ones used in ! publications. ! ! * Uses enhancements in Swarm's EZGraph (changes introduced since ! Swarm-2.1.1) to save output data as vectors in HDF5 files. This ! significantly enhances usage of output data files in statistical ! analysis programs. ! ! Bug fixes / code changes (see ChangeLog for details, or persue ! the patch from ASM-2.2 to ASM-2.4.) ! ! * closed memory leakes caused by use of probes in the getDouble() ! function in BFParams.m. ! ! * revised some of the scheduling apparatus to make the model run ! faster. ! ! * Fixed a misplaced bracked in BFagent's MakePool method. This ! was discovered and corrected by Thomas Badegruber. It significantly ! affects the performance of the genetic algorithm over the long run. ! ! * Coding for graphs and data output of hdf5 vectors for time plots ! was reorganized, significanly simplifying the shift from GUI to nonGUI ! models. Look in Output.m ! ! ! ASM-2.2 November 2001 ! ! This work was mainly aimed at documentation, inserting Autodoc markers ! so I can build nicer looking documentation. ! ! The only big substantive cleanup was in ASMModelSwarm. I had been ! avoiding this for a long time because the scheduling that was used was ! very complicated and hard to understand. I succeeded in a major ! simplicification and cleanup and have verified the numerical results ! are identical. This is explained in the beginning of ASMModelSwarm.m ! ! There was also a "procedural" cleanup of the code in World.m. The old ! version had a lot of callocs and other memory magic because it was ! keeping moving averages "by hand". This has been changed. There is ! now a MovingAverage class that is used to do that magic, so the code ! in World.m is much easier to read. ! ! There is much less low level math floating around. SNAP3: ASM 20011024 October 2001 The aim has been to bring this model into convenient Swarm standards. ! Actually, the real aim has been to make ASM an effective teaching tool ! and an example of good simulation coding practice. Part of that is a ! modernization of the data handling, both the input of parameter ! values, and record keeping of parameter values, as well as the saving ! of data. One of my pet peeves about Swarm is that we do not have a ! standard, idiot proof way to keep records on the settings and results ! are for a particular run. We also don't have fool proof ways to ! interate models and run simulations over again. The first problem is ! dealt with here in the Output class, and the second one is dealt with ! by the creation of a Parameter class, where we could manage command ! line parameters if we wanted to. 1. Inputting Parameter Values. *************** *** 143,163 **** - ASM-2.2 November 2001 - This work was mainly aimed at documentation, inserting Autodoc markers so I can build nicer looking documentation. ! The only big substantive cleanup was in ASMModelSwarm. I had been avoiding ! this for a long time because the scheduling that was used was very ! complicated and hard to understand. I succeeded in a major simplicification ! and cleanup and have verified the numerical results are identical. This is ! explained in the beginning of ASMModelSwarm.m - There was also a "procedural" cleanup of the code in World.m. The old - version had a lot of callocs and other memory magic because it was keeping - moving averages "by hand". This has been changed. There is now a MovingAverage - class that is used to do that magic, so the code in World.m is much easier to read. - There is much less low level math floating around. -------original readme follows This is the port to Swarm of the original NeXTstep version of --- 205,229 ---- ! SNAP2: ASM 20000602 June 2, 2000 ! Thorough workover of BFagent class, creating three new classes (BitVector, ! BFParams, and BFCast) and a massive reorganization of BFagent itself. ! See long comment in BFagent.m. ! ! ! ! ! SNAP1: May 7, 2000 ! In ASM-new-snap1, I've removed the random.h and random.m from this ! program, and replaced their functionality with Swarm library ! calls. Contrary to the statements below, this program should now ! behave like a Swarm app. Every time you run it, you get the same ! random seed, unless you use the command line switch or input a ! randomSeed of your own. ! -------original readme follows This is the port to Swarm of the original NeXTstep version of diff -rc ASM-2.2.1/Specialist.m ASM-2.4/Specialist.m *** ASM-2.2.1/Specialist.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/Specialist.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 119,129 **** volume = 0.0; - // Save previous values - //oldbidtotal = bidtotal; //pj: old variables were never used anywhere - //oldoffertotal = offertotal; - //oldvolume = volume; - dividend = [worldForSpec getDividend]; // Main loop on {set price, get demand} for (mcount = 0, done = NO; mcount < maxiterations && !done; mcount++) --- 119,124 ---- diff -rc ASM-2.2.1/World.h ASM-2.4/World.h *** ASM-2.2.1/World.h 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/World.h 2003-06-21 12:33:21.000000000 -0500 *************** *** 1,6 **** --- 1,12 ---- // The Santa Fe Stockmarket -- Interface for class World #import + #import + + + /*" Macro: number of world bits. Must match setup in World.m"*/ + #define NWORLDBITS 61 + /*" Macro: Number of up/down movements to store for price and dividend, including the current values. Used for pup, pup1, *************** *** 40,75 **** int malength[NMAS]; /*" For each MA, we must specify the length over which the average is calculated. This array has one integer for each of the moving averages we plan to keep, and it is used to set the widths covered by the moving averages."*/ int nworldbits; /*"The number of aspects of the world that are recorded as bits"*/ ! int * realworld; /*"An array (dynamically allocated, sorry) of ints, one for each bit being monitored. This is kept up-to-date. There's a lot of pointer math going on with this and I don't feel so glad about it (PJ: 2001-11-01)"*/ BOOL exponentialMAs; /*"Indicator variable, YES if the World is supposed to report back exponentially weighted moving averages"*/ ! id priceMA[NMAS]; /*" MovingAverage objects which hold price information. There are NMAS of these, and have various widths for the moving averages "*/ ! id divMA[NMAS]; /*" MovingAverage objects which hold dividend moving averages. "*/ ! id oldpriceMA[NMAS]; /*" MovingAverage objects which hold lagged price moving averages "*/ ! id olddivMA[NMAS];/*" MovingAverage objects which hold lagged dividend moving averages "*/ ! @private ! double * divhistory; /*" dividend history array, goes back MAXHISTORY points"*/ ! double * pricehistory; /*" price history array "*/ ! } ! +(const char *)descriptionOfBit: (int)n; ! +(const char *)nameOfBit: (int)n; ! +(int)bitNumberOf: (const char *)name; ! ! -setintrate: (double)rate; ! -setExponentialMAs: (BOOL)aBool; ! -(int)getNumWorldBits; ! ! -initWithBaseline: (double)base; ! -setPrice: (double)p; ! -(double)getPrice; ! -(double)getProfitPerUnit; ! -setDividend: (double)d; ! -(double)getDividend; ! -(double)getRiskNeutral; ! -updateWorld; ! -getRealWorld: (int *)anArray; ! -(int)pricetrend: (int)n; @end --- 46,83 ---- int malength[NMAS]; /*" For each MA, we must specify the length over which the average is calculated. This array has one integer for each of the moving averages we plan to keep, and it is used to set the widths covered by the moving averages."*/ int nworldbits; /*"The number of aspects of the world that are recorded as bits"*/ ! int realworld[NWORLDBITS]; ! // int * realworld; /*"An array (dynamically allocated, sorry) of ints, one for each bit being monitored. This is kept up-to-date. There's a lot of pointer math going on with this and I don't feel so glad about it (PJ: 2001-11-01)"*/ BOOL exponentialMAs; /*"Indicator variable, YES if the World is supposed to report back exponentially weighted moving averages"*/ ! id priceMA; /*" MovingAverage objects which hold price information. There are NMAS of these, and have various widths for the moving averages "*/ ! id divMA; /*" MovingAverage objects which hold dividend moving averages. "*/ ! id oldpriceMA; /*" MovingAverage objects which hold lagged price moving averages "*/ ! id olddivMA;/*" MovingAverage objects which hold lagged dividend moving averages "*/ ! @private ! //double * divhistory; /*" dividend history array, goes back MAXHISTORY points"*/ ! //double * pricehistory; /*" price history array "*/ ! double divhistory[MAXHISTORY] ; ! double pricehistory[MAXHISTORY] ; } ! + (const char *)descriptionOfBit: (int)n; ! + (const char *)nameOfBit: (int)n; ! + (int)bitNumberOf: (const char *)name; ! ! - setintrate: (double)rate; ! - setExponentialMAs: (BOOL)aBool; ! - (int)getNumWorldBits; ! ! - initWithBaseline: (double)base; ! - setPrice: (double)p; ! - (double)getPrice; ! - (double)getProfitPerUnit; ! - setDividend: (double)d; ! - (double)getDividend; ! - (double)getRiskNeutral; ! - updateWorld; ! - getRealWorld: (int *)anArray; ! - (int)pricetrend: (int)n; @end diff -rc ASM-2.2.1/World.m ASM-2.4/World.m *** ASM-2.2.1/World.m 2002-10-02 15:30:23.000000000 -0500 --- ASM-2.4/World.m 2003-06-21 12:33:21.000000000 -0500 *************** *** 24,30 **** #define irand(x) [uniformIntRand getIntegerWithMin: 0 withMax: x-1] /*" GETMA(x,j) is a macro that checks to see if we want an exponential MA or regular when we retrieve values from MA objects "*/ ! #define GETMA(x,j) exponentialMAs ? [x[j] getEWMA]:[x[j] getMA] /*" bitname struct holds the substantive information about various world indicators It is a list of bit names and descriptions --- 24,30 ---- #define irand(x) [uniformIntRand getIntegerWithMin: 0 withMax: x-1] /*" GETMA(x,j) is a macro that checks to see if we want an exponential MA or regular when we retrieve values from MA objects "*/ ! #define GETMA(x,j) exponentialMAs ? [[x atOffset: j] getEWMA]:[[x atOffset: j] getMA] /*" bitname struct holds the substantive information about various world indicators It is a list of bit names and descriptions *************** *** 113,119 **** }; ! #define NWORLDBITS (sizeof(bitnamelist)/sizeof(struct bitnamestruct)) #define NULLBIT -1 // The index of the "pup" bit --- 113,119 ---- }; ! //#define NWORLDBITS (sizeof(bitnamelist)/sizeof(struct bitnamestruct)) #define NULLBIT -1 // The index of the "pup" bit *************** *** 129,142 **** // ------ Private methods ------ @interface World(Private) ! -makebitvector; @end @implementation World ! /*" The World is a class that is mainly used to serve the information needs of BFagents. The WOrld takes price data and converts it into a number of trends, averages, and so forth. One instance of this object is created to manage the "world" variables -- the globally-visible variables that reflect the market itself, --- 129,144 ---- // ------ Private methods ------ @interface World(Private) ! - makebitvector; @end @implementation World ! /*" The World is a class that is mainly used to serve the information ! needs of BFagents. The World takes price data and converts it into ! a number of trends, averages, and so forth. One instance of this object is created to manage the "world" variables -- the globally-visible variables that reflect the market itself, *************** *** 156,162 **** { if (n == NULLBIT) return "(Unused bit for spacing)"; ! else if (n < 0 || n >= NWORLDBITS) return "(Invalid world bit)"; return bitnamelist[n].description; } --- 158,164 ---- { if (n == NULLBIT) return "(Unused bit for spacing)"; ! else if (n < 0 || n >= (int)NWORLDBITS) return "(Invalid world bit)"; return bitnamelist[n].description; } *************** *** 171,177 **** { if (n == NULLBIT) return "null"; ! else if (n < 0 || n >= NWORLDBITS) return ""; return bitnamelist[n].name; } --- 173,179 ---- { if (n == NULLBIT) return "null"; ! else if (n < 0 || n >= (int)NWORLDBITS) return ""; return bitnamelist[n].name; } *************** *** 183,189 **** * (linear search). Could be made faster with a hash table etc, but * that's not worth it for the intended usage. "*/ { ! int n; for (n = 0; n < NWORLDBITS; n++) if (strcmp(name,bitnamelist[n].name) == EQ) --- 185,191 ---- * (linear search). Could be made faster with a hash table etc, but * that's not worth it for the intended usage. "*/ { ! unsigned n; for (n = 0; n < NWORLDBITS; n++) if (strcmp(name,bitnamelist[n].name) == EQ) *************** *** 228,233 **** --- 230,242 ---- int i; double initprice, initdividend; + + priceMA = [Array create: [self getZone] setCount: NMAS]; + oldpriceMA = [Array create: [self getZone] setCount: NMAS]; + divMA = [Array create: [self getZone] setCount: NMAS]; + olddivMA = [Array create: [self getZone] setCount: NMAS]; + + // Check pup index if (strcmp([World nameOfBit:PUPDOWNBITNUM], "pup") != EQ) printf("PUPDOWNBITNUM is incorrect"); *************** *** 256,294 **** history_top = 0; updown_top = 0; ! divhistory = [[self getZone] alloc: MAXHISTORY*sizeof(double)]; ! pricehistory = [[self getZone] alloc: MAXHISTORY*sizeof(double)]; ! realworld = calloc(NWORLDBITS, sizeof(int)); if(!realworld) printf("Error allocating memory for realworld."); // Initialize arrays for (i = 0; i < UPDOWNLOOKBACK; i++) { ! pupdown[i] = 0; ! dupdown[i] = 0; } for (i = 0; i < MAXHISTORY; i++) { ! pricehistory[i] = initprice; ! divhistory[i] = initdividend; } for (i = 0; i < NMAS; i++) { ! priceMA[i] = [MovingAverage create: [self getZone]]; ! [priceMA[i] initWidth: malength[i] Value: initprice]; ! ! divMA[i] = [MovingAverage create: [self getZone]]; ! [divMA[i] initWidth: malength[i] Value: initdividend]; ! ! oldpriceMA[i] = [MovingAverage create: [self getZone]]; ! [oldpriceMA[i] initWidth: malength[i] Value: initprice]; ! ! olddivMA[i] = [MovingAverage create: [self getZone]]; ! [olddivMA[i] initWidth: malength[i] Value: initdividend]; } // Initialize bits --- 265,312 ---- history_top = 0; updown_top = 0; ! //divhistory = [[self getZone] alloc: MAXHISTORY*sizeof(double)]; ! //pricehistory = [[self getZone] alloc: MAXHISTORY*sizeof(double)]; ! // realworld = calloc(NWORLDBITS, sizeof(int)); if(!realworld) printf("Error allocating memory for realworld."); // Initialize arrays for (i = 0; i < UPDOWNLOOKBACK; i++) { ! pupdown[i] = 0; ! dupdown[i] = 0; } for (i = 0; i < MAXHISTORY; i++) { ! pricehistory[i] = initprice; ! divhistory[i] = initdividend; } for (i = 0; i < NMAS; i++) { ! { ! MovingAverage * prMA = [MovingAverage create: [self getZone]]; ! [prMA initWidth: malength[i] Value: initprice]; ! [priceMA atOffset: i put: prMA]; ! } ! { ! MovingAverage * dMA = [MovingAverage create: [self getZone]]; ! [dMA initWidth: malength[i] Value: initdividend]; ! [divMA atOffset: i put: dMA]; ! } ! { ! MovingAverage * oldpMA = [MovingAverage create: [self getZone]]; ! [oldpMA initWidth: malength[i] Value: initprice]; ! [oldpriceMA atOffset: i put: oldpMA]; ! } ! { ! MovingAverage * olddMA = [MovingAverage create: [self getZone]]; ! [olddMA initWidth: malength[i] Value: initdividend]; ! [olddivMA atOffset: i put: olddMA]; ! } } // Initialize bits *************** *** 395,405 **** { int rago = (history_top-malength[i])%MAXHISTORY; ! [priceMA[i] addValue: price]; ! [divMA[i] addValue: dividend]; ! [oldpriceMA[i] addValue: pricehistory[rago]]; ! [olddivMA[i] addValue: divhistory[rago]]; } --- 413,423 ---- { int rago = (history_top-malength[i])%MAXHISTORY; ! [[priceMA atOffset: i] addValue: price]; ! [[divMA atOffset: i] addValue: dividend]; ! [[oldpriceMA atOffset:i] addValue: pricehistory[rago]]; ! [[olddivMA atOffset: i] addValue: divhistory[rago]]; } *************** *** 416,427 **** - makebitvector ! /*" Set all the world bits, based on the current dividend, price, ! and their moving averages and histories. This moves through the ! realworld array, bit by bit, setting the values to 0, 1 or 2, ! according to the data that has been observed. Note the pointer math, such as realworld[i++], that steps the integer i through the array. Note that "i" increases monotonically throughout this routine, always ! being the next bit to assign. It is crucial that the order here is the ! same as in bitnamelist[]. "*/ { register int i, j, k, temp; double multiple; --- 434,447 ---- - makebitvector ! /*" Set all the world bits, based on the current dividend, price, and ! their moving averages and histories. This moves through the realworld ! array, bit by bit, setting the values to 0, 1 or 2, according to the ! data that has been observed. Note the pointer math, such as ! realworld[i++], that steps the integer i through the array. Note that ! "i" increases monotonically throughout this routine, always being the ! next bit to assign. It is crucial that the order here is the same as ! in bitnamelist[]. "*/ { register int i, j, k, temp; double multiple; *************** *** 451,468 **** for (j = 0; j < NMAS-1; j++) for (k = j+1; k < NMAS; k++) realworld[i++] = (GETMA(divMA,j)) > (GETMA(divMA,k)); - // realworld[i++] = exponentialMAs ? [divMA[j] getEWMA]:[divMA[j] getMA] > exponentialMAs ? [divMA[k] getEWMA]:[divMA[k] getMA]; - //realworld[i++] = dmav[j] > dmav[k]; /* Dividend as multiple of meandividend */ multiple = dividend/dividendscale; ! for (j = 0; j < NRATIOS; j++) realworld[i++] = multiple > ratios[j]; /* Price as multiple of dividend/intrate. Here we use olddividend to * make a more reasonable comparison with the [old] price. */ multiple = price*intrate/olddividend; ! for (j = 0; j < NRATIOS; j++) realworld[i++] = multiple > ratios[j]; /* Price went up or down, now and for last few periods */ --- 471,486 ---- for (j = 0; j < NMAS-1; j++) for (k = j+1; k < NMAS; k++) realworld[i++] = (GETMA(divMA,j)) > (GETMA(divMA,k)); /* Dividend as multiple of meandividend */ multiple = dividend/dividendscale; ! for (j = 0; j < (int)NRATIOS; j++) realworld[i++] = multiple > ratios[j]; /* Price as multiple of dividend/intrate. Here we use olddividend to * make a more reasonable comparison with the [old] price. */ multiple = price*intrate/olddividend; ! for (j = 0; j < (int)NRATIOS; j++) realworld[i++] = multiple > ratios[j]; /* Price went up or down, now and for last few periods */ *************** *** 478,485 **** /* Price > MA[j] */ for (j = 0; j < NMAS; j++) realworld[i++] = price > (GETMA(priceMA,j)); - // realworld[i++] = price > exponentialMAs ? [priceMA[j] getEWMA]:[priceMA[j] getMA]; - // realworld[i++] = price > pmav[j]; /* Price MA[j] > price MA[k] */ for (j = 0; j < NMAS-1; j++) --- 496,501 ---- *************** *** 495,501 **** * no -> 2 (10) * Then we're able to check rule satisfaction with simple ANDs. */ ! for (i = 0; i < NWORLDBITS; i++) realworld[i] = 2 - realworld[i]; return self; --- 511,517 ---- * no -> 2 (10) * Then we're able to check rule satisfaction with simple ANDs. */ ! for (i = 0; i < (int)NWORLDBITS; i++) realworld[i] = 2 - realworld[i]; return self;