Only in ASM-20000507: .libs diff -cb --unidirectional-new-file ASM-20000507/ASMModelSwarm.h ASM-20000602/ASMModelSwarm.h *** ASM-20000507/ASMModelSwarm.h Sun May 7 14:11:44 2000 --- ASM-20000602/ASMModelSwarm.h Fri Jun 2 11:03:37 2000 *************** *** 86,92 **** -warmupStepDividend; -warmupStepPrice; -periodStepDividend; ! -prepareBFagentForTrading; -periodStepPrice; --- 86,92 ---- -warmupStepDividend; -warmupStepPrice; -periodStepDividend; ! //-prepareBFagentForTrading; -periodStepPrice; diff -cb --unidirectional-new-file ASM-20000507/ASMModelSwarm.m ASM-20000602/ASMModelSwarm.m *** ASM-20000507/ASMModelSwarm.m Sun May 7 14:11:44 2000 --- ASM-20000602/ASMModelSwarm.m Fri Jun 2 11:03:37 2000 *************** *** 2,11 **** --- 2,16 ---- #import #import "Output.h" //#import "random.h" + #import "BFParams.h" + #import "BFCast.h" + #import #include + + @implementation ASMModelSwarm +createBegin: (id)aZone *************** *** 209,214 **** --- 214,220 ---- -buildObjects //Build and initialize all objects { int i; + id bfParams; /* Initialise random number stream (0 means set randomly) */ //pj *************** *** 262,268 **** --- 268,283 ---- agentList = [List create: [self getZone]]; //create list for agents + if ((bfParams = + [lispAppArchiver getWithZone: self key: "bfParams"]) == nil) + raiseEvent(InvalidOperation, + "Can't find the modelSwarm parameters"); + [bfParams init]; + [BFagent init]; + + [BFagent setBFParameterObject: bfParams]; + //[BFagent init]; [BFagent setWorld: world]; //nowObject create the agents themselves *************** *** 281,287 **** [agentList addLast: agent]; } ! [BFagent didInitialize]; //Give the specialist access to the agentList --- 296,302 ---- [agentList addLast: agent]; } ! // [BFagent didInitialize]; //Give the specialist access to the agentList *************** *** 336,343 **** message: M(updateWorld)]; // Tell BFagent class to prepare for trading ! [periodActions createActionTo: self ! message: M(prepareBFagentForTrading)]; // Tell BFagents to get ready for trading (they may run GAs here) [periodActions createActionForEach: agentList --- 351,358 ---- message: M(updateWorld)]; // Tell BFagent class to prepare for trading ! //pj: [periodActions createActionTo: self ! //pj: message: M(prepareBFagentForTrading)]; // Tell BFagents to get ready for trading (they may run GAs here) [periodActions createActionForEach: agentList *************** *** 441,451 **** } ! -prepareBFagentForTrading ! { ! [BFagent prepareForTrading]; ! return self; ! } -periodStepPrice --- 456,466 ---- } ! //-prepareBFagentForTrading ! //pj:{ ! //pj:[BFagent prepareForTrading]; ! //pj: return self; ! //pj:} -periodStepPrice diff -cb --unidirectional-new-file ASM-20000507/Agent.h ASM-20000602/Agent.h *** ASM-20000507/Agent.h Sun May 7 14:11:44 2000 --- ASM-20000602/Agent.h Thu May 25 13:22:37 2000 *************** *** 1,6 **** #import //Agent is a SwarmObject #import "World.h" - @interface Agent:SwarmObject { --- 1,6 ---- #import //Agent is a SwarmObject + #import #import "World.h" @interface Agent:SwarmObject { diff -cb --unidirectional-new-file ASM-20000507/BFCast.h ASM-20000602/BFCast.h *** ASM-20000507/BFCast.h Wed Dec 31 18:00:00 1969 --- ASM-20000602/BFCast.h Fri Jun 2 11:03:37 2000 *************** *** 0 **** --- 1,129 ---- + #import + #import "BitVector.h" + + + + @interface BFCast: SwarmObject + { + double forecast; // this forecast of return + double lforecast; // previous forecast + double variance; // variance of this forecast + double strength; + double a; // (price + dividend) coefficient + double b; // dividend coefficient + double c; // constant term + double specfactor; // specificity factor; strength=specfactor/variance + double bitcost; + + // struct BF_fcast *next; // linked list of ACTIVE forecasts + // struct BF_fcast *lnext; + BitVector *conditions; + int lastactive; + int specificity; + int count; + int condwords; + int condbits; + int nnulls; + }; + + + - createEnd; + + -(void) incrSpecificity; + + -(void) decrSpecificity; + + -(void) setSpecificity: (int) specificity; + + -(int) getSpecificity; + + -(void) setConditions: (int *) x; + + -(int *) getConditions; + + -(BitVector *) getConditionsObject; + + - (void) setNNulls: (int) x; + + - (void) setBitcost: (double) x; + + -(void) setConditionsWord: (int) i To: (int) value; + + -(int) getConditionsWord: (int) x; + + -(void) setConditionsbit: (int) bit To: (int) x; //works for 0,1,2 + + -(void) setConditionsbit: (int) bit FromZeroTo: (int) x;//faster if cond[bit]=0 + + -(void) maskConditionsbit: (int) bit; + + -(void) switchConditionsbit: (int) bit; + + -(int) getConditionsbit: (int)bit; + + -(void) setAval: (double) x; + + -(void) setBval: (double) x; + + -(void) setCval: (double) x; + + - (double) getAval; + + - (double) getBval; + + - (double) getCval; + + -(void) updateSpecfactor; + + -(void) setSpecfactor: (double) x; + + - (double) getSpecfactor; + + - (void) setVariance: (double) x; + + -(double) getVariance; + + -(void) setCondwords: (int) x; + + -(void) setCondbits: (int) x; + + -(void) setForecast: (double) x; + + - (double) getForecast; + + -(double) updateForecastPrice: (double) price Dividend: (double) dividend; + + -(void) setLforecast: (double) x; + + - (double) getLforecast; + + -(void) setLastactive: (int) x; + + -(int) getLastactive; + + -(void) setCnt: (int) x; + + -(int) getCnt; + + - (int) incrCount; + + -(void) setStrength: (double) x; + + - (double) getStrength; + + - copyEverythingFrom: (BFCast *) from; + + - print; + + - printcond: (int) conditions; + + -(void) drop; + + @end + + + + + + + diff -cb --unidirectional-new-file ASM-20000507/BFCast.m ASM-20000602/BFCast.m *** ASM-20000507/BFCast.m Wed Dec 31 18:00:00 1969 --- ASM-20000602/BFCast.m Fri Jun 2 11:03:37 2000 *************** *** 0 **** --- 1,318 ---- + #import "BFCast.h" + #import "BFParams.h" + + @implementation BFCast + + - 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; + } + + + init + { + [BitVector init]; + return self; + } + + -(void) drop + { + [conditions drop]; + [super drop]; + } + + + -(void) setCondwords: (int) x + { + condwords = x; + } + + -(void) setCondbits: (int) x + { + condbits=x; + } + + - (void) setNNulls: (int) x + { + nnulls= nnulls; + } + + - (void) setBitcost: (double) x + { + bitcost = x; + } + + + -(void) setConditions: (int *) x + { + [conditions setConditions: x]; + } + + -(int *) getConditions + { + return [conditions getConditions]; + } + + + -(BitVector *) getConditionsObject + { + return conditions; + } + + + -(void) setConditionsWord: (int) i To: (int) value + { + [conditions setConditionsWord: i To: value]; + } + + + -(int) getConditionsWord: (int) x + { + return [conditions getConditionsWord: x]; + } + + + -(void) setConditionsbit: (int) bit To: (int) x + { + [conditions setConditionsbit: bit To: x]; + } + + + -(void) setConditionsbit: (int) bit FromZeroTo: (int) x + { + [conditions setConditionsbit: bit FromZeroTo: x]; + } + + + -(int) getConditionsbit: (int)bit + { + return [conditions getConditionsbit: bit]; + } + + + -(void) maskConditionsbit: (int) bit + { + // conditions[WORD(bit)] &= NMASK[bit]; + // specificity --; + [conditions maskConditionsbit: bit]; + } + + -(void) switchConditionsbit: (int) bit + { + // conditions[WORD(bit)] ^= MASK[bit]; + [conditions switchConditionsbit: bit]; + } + + -(void) setAval: (double) x + { + a=x; + } + + -(void) setBval: (double) x + { + b=x; + } + + -(void) setCval: (double) x + { + c=x; + } + + + - (double) getAval + { + return a; + } + + + - (double) getBval + { + return b; + } + + - (double) getCval + { + return c; + } + + -(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 + + } + + -(void) setSpecfactor: (double) x + { + specfactor=x; + }; + + + - (double) getSpecfactor + { + return specfactor; + } + + + -(void) incrSpecificity + { + ++ specificity; + } + + + -(void) decrSpecificity + { + --specificity; + } + + + -(void) setSpecificity: (int) x + { + specificity=x; + } + + -(int) getSpecificity + { + return specificity; + } + + -(void) setVariance: (double) x + { + variance=x; + } + + -(double) getVariance + { + return variance; + } + + + -(void) setLastactive: (int) x + { + lastactive=x; + } + + -(int) getLastactive + { + return lastactive; + + } + + - (int) getCnt + { + return count; + } + + + -(void) setCnt: (int) x + { + count = x; + + } + + - (int) incrCount; + { + return ++count; + } + + - (double) getStrength + { + return strength; + } + + + -(void) setStrength: (double) x + { + strength=x; + } + + + -(void) setLforecast: (double) x + { + lforecast=x; + } + + - (double) getLforecast + { + return lforecast; + } + + + + -(void) setForecast: (double) x + { + forecast=x; + } + + - (double) getForecast + { + return forecast; + } + + -(double) updateForecastPrice: (double) price Dividend: (double) dividend + { + lforecast=forecast; + forecast= a* (price+dividend) + b*dividend + c; + return forecast; + } + + + - copyEverythingFrom: (BFCast *) from + { + forecast= [from getForecast]; + lforecast = [from getLforecast]; + variance = [from getVariance]; + strength = [from getStrength]; + a= [from getAval]; + b= [from getBval]; + c= [from getCval]; + specfactor = [from getSpecfactor]; + lastactive =[from getLastactive]; + specificity = [from getSpecificity]; + count = [from getCnt]; + [self setConditions: [from getConditions]]; + return self; + } + + - print + { + int word; + printf("BFCast print: forecast %f lforecast %f variance %f strength %f \n",forecast,lforecast,variance,strength); + for ( word=0; word < condwords; word++) + [self printcond: word]; + printf("a %f b %f c %f specfactor %f, specificity %d count %d lastactive %d \n", a,b,c,specfactor,specificity,count,lastactive); + + return self; + } + + - printcond: (int) word + { + [conditions printcond: word]; + return self; + } + + + + + @end + + + + + + + + + + diff -cb --unidirectional-new-file ASM-20000507/BFParams.h ASM-20000602/BFParams.h *** ASM-20000507/BFParams.h Wed Dec 31 18:00:00 1969 --- ASM-20000602/BFParams.h Thu May 25 13:22:37 2000 *************** *** 0 **** --- 1,80 ---- + #import + + + //Macros for bittables + #define WORD(bit) (bit>>4) + #define MAXCONDBITS 80 + + + id + makeProbe (id obj, const char *ivarName); + + double + getDouble (id obj, const char *ivarName); + + int + getInt (id obj, const char *ivarName); + + + @interface BFParams: SwarmObject + { + @public + int numfcasts; + int condwords; + int condbits; + int mincount; + int gafrequency; + int firstgatime; + int longtime; // unused time before Generalize() + int individual; + double tauv; + double lambda; + double maxbid; + double bitprob; + double subrange; // fraction of min-max range for initial random values + double a_min,a_max; // min and max for p+d coef + double b_min,b_max; // min and max for div coef + double c_min,c_max; // min and max for constant term + double a_range,b_range,c_range; // derived: max - min + double newfcastvar; // variance assigned to a new forecaster + double initvar; // variance of overall forecast for t<200 + double bitcost; // penalty parameter for specificity + double maxdev; // max deviation of a forecast in variance estimation + double poolfrac; // fraction of rules in replacement pool + double newfrac; // fraction of rules replaced + double pcrossover; // probability of running Crossover() at all. + double plinear; // linear combination "crossover" prob. + double prandom; // random from each parent crossover prob. + double pmutation; // per bit mutation prob. + double plong; // long jump prob. + double pshort; // short (neighborhood) jump prob. + double nhood; // size of neighborhood. + double genfrac; // fraction of 0/1 bits to generalize + double gaprob; // derived: 1/gafrequency + int npool; // derived: replacement pool size + int nnew; // derived: number of new rules + int nnulls; + int lastgatime; + int *bitlist; // dynamic array, length condbits + double *problist; // dynamic array, length condbits + unsigned int *myworld;// dynamic array, length condwords + + int npoolmax ; /* size of reject array */ + int nnewmax ; /* size of newfcast array */ + int ncondmax; /* size of newc*/ + + }; + + + -init; + + -(int*) getBitListPtr; + + - (double *) getProbListPtr; + + - (int *) getMyworldPtr; + + -(int)lastgatime; + + + @end diff -cb --unidirectional-new-file ASM-20000507/BFParams.m ASM-20000602/BFParams.m *** ASM-20000507/BFParams.m Wed Dec 31 18:00:00 1969 --- ASM-20000602/BFParams.m Fri Jun 2 13:01:21 2000 *************** *** 0 **** --- 1,188 ---- + #import "BFParams.h" + #import "World.h" + #import + + + // Values in table of special bit names (negative, avoiding NULLBIT) + #define ENDLIST -2 + #define ALL -3 + #define SETPROB -4 + #define BADINPUT -5 + #define NOTFOUND -6 + #define EQ 0 + #define NULLBIT -1 + + struct keytable + { + const char *name; + int value; + }; + + static struct keytable specialbits[] = + { + {"null", NULLBIT}, + {"end", ENDLIST}, + {".", ENDLIST}, + {"all", ALL}, + {"allbits", ALL}, + {"p", SETPROB}, + {"P", SETPROB}, + {"???", BADINPUT}, + {NULL, NOTFOUND} + }; + + int ReadBitname(const char *variable, const struct keytable *table); + + id + makeProbe (id obj, const char *ivarName) + { + id probe = [VarProbe createBegin: [obj getZone]]; + [probe setProbedClass: [obj getClass]]; + [probe setProbedVariable: ivarName]; + 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) + { + id probe = makeProbe (obj, ivarName); + int ret = [probe probeAsInt: obj]; + [probe drop]; + return ret; + } + + + @implementation BFParams + + -(int)lastgatime + { + return lastgatime; + } + + + -init + { + int i; + + int bits[MAXCONDBITS]; + // double probs[MAXCONDBITS]; + + bitlist= [ [self getZone] allocBlock: condbits * sizeof(int) ]; + problist=[ [self getZone] allocBlock: condbits * sizeof(double) ]; + + bits[0] = ReadBitname("pr/d>1/4", specialbits); + bits[1] = ReadBitname("pr/d>1/2", specialbits); + bits[2] = ReadBitname("pr/d>3/4", specialbits); + 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); + + for (i=0; i < condbits; i++) + { + bitlist[i] = bits[i]; + //params->problist[i] = probs[i]; + problist[i] = bitprob; + } + + + // Allocate space for our world bits, clear initially + + 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."); + + // Compute derived parameters + gaprob = 1.0/(double)gafrequency; + a_range = a_max - a_min; + b_range = b_max - b_min; + c_range = c_max - c_min; + + npool = (int)(numfcasts*poolfrac + 0.5); + nnew = (int)(numfcasts*newfrac + 0.5); + + // Record maxima needed for GA working space + if (npool > npoolmax) npoolmax = npool; + if (nnew > nnewmax) nnewmax = nnew; + if (condwords > ncondmax) ncondmax = condwords; + fprintf(stderr,"BFParams init complete"); + return self; + } + + -(int*) getBitListPtr + { + return bitlist; + } + + - (double *) getProbListPtr + { + return problist; + } + + - (int *) getMyworldPtr + { + return myworld; + } + + + int ReadBitname(const char *variable, const struct keytable *table) + /* + * Like ReadKeyword, but looks up the name first as the name of a bit + * and then (if there's no match) in table if it's non-NULL. + */ + { + const struct keytable *ptr; + int n; + + n = [World bitNumberOf: variable]; + + if (n < 0 && table) + { + for (ptr=table; ptr->name; ptr++) + if (strcmp(variable,ptr->name) == EQ) + break; + if (!ptr->name && strcmp(variable,"???") != EQ) + printf("unknown keyword '%s'\n",variable); + n = ptr->value; + } + return n; + } + + + @end + + + + + + + + + + + diff -cb --unidirectional-new-file ASM-20000507/BFagent.h ASM-20000602/BFagent.h *** ASM-20000507/BFagent.h Sun May 7 14:11:44 2000 --- ASM-20000602/BFagent.h Fri Jun 2 13:01:21 2000 *************** *** 1,69 **** // Interface for BFagent -- Classifier predictors #import "Agent.h" - // Structure for list of individual forecasts - struct BF_fcast - { - double forecast; // this forecast of return - double lforecast; // previous forecast - double variance; // variance of this forecast - double strength; - double a; // (price + dividend) coefficient - double b; // dividend coefficient - double c; // constant term - double specfactor; // specificity factor; strength=specfactor/variance - struct BF_fcast *next; // linked list of ACTIVE forecasts - struct BF_fcast *lnext; - unsigned int *conditions; - int lastactive; - int specificity; - int count; - }; ! struct BFparams ! { ! int numfcasts; ! int condwords; ! int condbits; ! int mincount; ! int gafrequency; ! int firstgatime; ! int longtime; // unused time before Generalize() ! int individual; ! double tauv; ! double lambda; ! double maxbid; ! double bitprob; ! double subrange; // fraction of min-max range for initial random values ! double a_min,a_max; // min and max for p+d coef ! double b_min,b_max; // min and max for div coef ! double c_min,c_max; // min and max for constant term ! double a_range,b_range,c_range; // derived: max - min ! double newfcastvar; // variance assigned to a new forecaster ! double initvar; // variance of overall forecast for t<200 ! double bitcost; // penalty parameter for specificity ! double maxdev; // max deviation of a forecast in variance estimation ! double poolfrac; // fraction of rules in replacement pool ! double newfrac; // fraction of rules replaced ! double pcrossover; // probability of running Crossover() at all. ! double plinear; // linear combination "crossover" prob. ! double prandom; // random from each parent crossover prob. ! double pmutation; // per bit mutation prob. ! double plong; // long jump prob. ! double pshort; // short (neighborhood) jump prob. ! double nhood; // size of neighborhood. ! double genfrac; // fraction of 0/1 bits to generalize ! double gaprob; // derived: 1/gafrequency ! int npool; // derived: replacement pool size ! int nnew; // derived: number of new rules ! int nnulls; ! int lastgatime; ! int *bitlist; // dynamic array, length condbits ! double *problist; // dynamic array, length condbits ! unsigned int *myworld;// dynamic array, length condwordsdouble avspecificity ! }; @interface BFagent:Agent { --- 1,18 ---- // Interface for BFagent -- Classifier predictors #import "Agent.h" + #import "BFParams.h" + #import "BFCast.h" + #import + #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 { *************** *** 78,101 **** double pdcoeff; double offset; double divisor; ! struct BF_fcast *fcast; // array of size numfcasts ! struct BF_fcast *activelist; ! struct BF_fcast *lactivelist; // last active list ! struct BFparams *p; int gacount; int nactive; } ! +(void *)init; ! +didInitialize; ! +prepareForTrading; ! +(int)lastgatime; +setRealWorld: (int *)array; +(int)setNumWorldBits; -initForecasts; ! -free; -prepareForTrading; -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; --- 27,69 ---- double pdcoeff; double offset; double divisor; ! // struct BF_fcast *fcast; // array of size numfcasts ! //struct BF_fcast *activelist; ! //struct BF_fcast *lactivelist; // last active list ! // struct BFparams *p; int gacount; int nactive; + BFParams * privateParams; //created from same mechanism as public params + // struct BF_fcast **reject; /* GA temporary storage */ + // struct BF_fcast *newfcast; /* GA temporary storage */ + //id rejectList; //need ** accounted for ??? + + id fcastList; + //id newconds; + + id activeList; + id oldActiveList; } ! +(void)setBFParameterObject: x; ! +(void)init; ! //+didInitialize; ! //+prepareForTrading; ! //+(int)lastgatime; +setRealWorld: (int *)array; +(int)setNumWorldBits; + -createEnd; -initForecasts; ! ! - (BFCast *) createNewForecast; //all conditions=0 ! ! -setConditionsRandomly: (BFCast *) fcastObject; //apply to forecast ! //-free; -prepareForTrading; + -(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; *************** *** 106,116 **** --- 74,90 ---- -(int)nbits; -(int)nrules; -(int)lastgatime; + + -printcond: (int) word; + + - copyList: list To: outputList; + -(int)bitDistribution:(int *(*)[4])countptr cumulative:(BOOL)cum; -(int)fMoments: (double *)moment cumulative: (BOOL)cum; -(const char *)descriptionOfBit:(int)bit; @end + diff -cb --unidirectional-new-file ASM-20000507/BFagent.m ASM-20000602/BFagent.m *** ASM-20000507/BFagent.m Sun May 7 14:11:44 2000 --- ASM-20000602/BFagent.m Fri Jun 2 13:01:21 2000 *************** *** 8,27 **** // Tells the agent class object that initialization (including creation // of agents) is finished. // ! // +prepareForTrading ! // Sent for each type of this class, announcing the start of a new ! // trading period. The class object can use this to set up any common ! // information for use by getDemandandSlope:forPrice: etc. The ! // pointer to "params" identifies the particular type. These class ! // messages are follwed by -prepareForTrading messages to each ! // enabled instance. ! // // +(BOOL)lastgatime // Returns the most recent time at which a GA ran for any agent of // this type. // ! // -free ! // frees space used by forecast lists // // -(int *(*)[4])bitDistribution; // Returns a pointer to an array of 4 pointers to arrays containing the --- 8,20 ---- // Tells the agent class object that initialization (including creation // of agents) is finished. // ! // +prepareForTrading //deleted by pj May 1, 2000 ! // +(BOOL)lastgatime // Returns the most recent time at which a GA ran for any agent of // this type. // ! // -free //now handled by "drop" method in "BFCast.m" // // -(int *(*)[4])bitDistribution; // Returns a pointer to an array of 4 pointers to arrays containing the *************** *** 62,74 **** --- 55,235 ---- // arrays to which its element point are supplied dynamically. This // method must be provided by each subclass that has condition bits. // + /* + pj: change comments June 2, 2000 + + I began with the code as released by the ASM research team through + Brandon Weber in April, 2000. Here is a summary of the vital changes + that affect the BFagent class. + + 0. New classes used in this version: + A. BFCast.[hm] + B. BFParams.[hm] + C. BitVector.[hm] + + 1. I am fully aware of confusion about the meaning of bit in this + model. Bit does usually mean something that is 0 or 1, but in this + model it means something else. In the agent, a bit is what is often + called a "trit", something that is valued 00, 01, 10, or 11. Trit + means smallest thing that can hold three values. In these agents, a + trit has these meanings: + + binary value integer equivalent meaning + 00 0 # or "don't care" + 01 1 NO + 10 2 YES + 11 3 not in use, a place holder value + + GET READY for the big surprise. In World.m, the coding is reversed, so + 01 means yes and 10 means no. This accelerates the comparision of the + agent's bit vector against the state of the world. Look for the & in + the-updateActiveList: medthod and you'll see why. I've written an + alternative, more transparent algorithm. I don't think it takes much + more time, but perhaps your computer will tell differently. + + 2. The bit math got frustrating enough that I have segregated it in a + class I call "BitVector". It is really a vector of "trits" but so + much of the rest of this code uses the term bit that I didn't have the + enthusiasm to change it. When a "BitVector" instance is created, it + has to be told how many bits, er trits, of information it is supposed + to hold. Whenever the agent needs to keep track of a bunch of bits, + er trits, it can create a BitVector object to do it, and the interface + allows values to be put in and retrieved in a relatively obvious way. + + Furthermore, when agents create the "forecast objects" using the + BFCast class, then those forecast objects will contain within them + BitVector objects that keep track of that forcast's object's bits. + + 3. The BFCast class now has taken the place of the struct BF_cast that + was in BFagent.h. Any bit manipulation that needs to be done can be + done by talking to an instance of that class. The bit manipulation is + hidden from this BFagent class, so at some time in the future we could + re-implement BFCast and as long as it had the right interface, the + BFagent would not care. The BFCast class talks to the forecast object + that is inside it and tells it to set bits (er, trits) to certain + values with messages like "setConditionsbit: 5 To: 2" and BFCast can + handle the rest by passing on the news to the BitVector object. + + 4. The BFParams class now has taken the place of the struct BF_Params + that was in BFagent. This change allows some significant upgrades in + functionality. First, the BFParams class uses the Swarm + lispAppArchiver. See the initial values in asm.scm. Because the + BFParams object contains some variables that are derived from the + values in the archiver, it is necessary to send an "init" message + after creating a BFParams object. Second, it is now possible to + customize the agents by creating a customized BFParams object for each + agent. In the original ASM-2.0 code, there is a "global" variable + params and all agents use that one set of parameters. So far, I not + done much to investigate the advantages of allowing agents to use + different numbers of bits (er, trits), but I intend to. Until I do + that, the instance variable "privateParams" simply points to the same + single BFParams object that is created by ASMModelSwarm, and + parameters retrieved from either are thus the same. + + Note further, I did not write "get" methods for every + variable in the BFParams class. It just seemed onerous to do so. + There are 2 ways to get values out of BFParams. First, use the ->. I + declared the IVARS in BFParams to be public, so they can be retrieved + with the symbol -> as if the parameter object were a pointer to a + struct, as in: privateParams->condwords. I hate doing that, and have + the long term plan of replacing all of these usages with get messages. + Second, for the short term, I put in the getDouble() and getInt() + functions which can be used to do get values. These will work even for + private variables, so if you get concerned about declaring all those + public IVARS in BFParams, you can get values in this way: + getInt(privateParams,"condwords"). I used that a number of times in + this file, but not everywhere, because I got tired of typing. + + + 5. More object orientation. The "homemade" linked lists, built with + pointers and other C concepts, are replaced by Swarm collections. + 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. + + Usage of pointers to arrays is now minimized as well. There used to + be a class method called +prepareForTrading that would retrieve a copy + of all the world's information and pick out what was needed for an + agent of this class. Then the result of that calculation would get + stored in world. While this had the advantage of doing the + calculation once for all agents of the class, it has the disadvantage + of restricting us to having identical bit vectors in all agent + forecasts. I've dropped this approach, instead creating a variable + myworld in the agent's -prepareForTrading method, and each agent can + look to the world and get the information it wants. + + + 6. Think locally, act locally. Global pointers and lists and anything + else have been replaced wherever possible by automatic variables + (inside methods) or instance variables. I created several new methods + that take bits from bit methods/functions and do them in isolation + (see -updateActiveList or -collectWorldData. + + 7. Genetic Algorithm now is written in Obj-C methods that pass whatever + arguments are needed, rather than using C functions that access a lot + of global variables. Agent's don't share workspace for the GA, either, + each has its own memory. + + 8. Formulas to calcuate strength, specfactor, and variance in the + forecast objects were different in the original BFagent.m than in + the bfagent.m. Since the bfagent.m file matched the documentation + released with ASM-2.0, I have changed to use the bfagent.m formulas + in this file. Some cleanup can still be made. */ + #import "BFagent.h" #import #import "World.h" #include + #import "BFParams.h" + #import "BFCast.h" + #import "BitVector.h" 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: //convenience macros to replace stuff from ASM random with Swarm random stuff *************** *** 77,472 **** #define urand() [uniformDblRand getDoubleWithMin: -1 withMax: 1] #define irand(x) [uniformIntRand getIntegerWithMin: 0 withMax: x-1] ! //Macros for bittables ! #define WORD(bit) (bit>>4) ! #define MAXCONDBITS 80 ! ! extern int SHIFT[MAXCONDBITS]; ! extern unsigned int MASK[MAXCONDBITS]; ! extern unsigned int NMASK[MAXCONDBITS]; ! ! int SHIFT[MAXCONDBITS]; ! unsigned int MASK[MAXCONDBITS]; ! unsigned int NMASK[MAXCONDBITS]; // Type of forecasting. WEIGHTED forecasting is untested in its present form. #define WEIGHTED 0 ! struct keytable ! { ! const char *name; ! int value; ! }; ! ! struct keytable individualkeys[] = ! { ! {"yes", 1}, ! {"no", 0}, ! {NULL, -1} ! }; ! ! // Values in table of special bit names (negative, avoiding NULLBIT) ! #define ENDLIST -2 ! #define ALL -3 ! #define SETPROB -4 ! #define BADINPUT -5 ! #define NOTFOUND -6 ! #define EQ 0 ! #define NULLBIT -1 ! ! static struct keytable specialbits[] = ! { ! {"null", NULLBIT}, ! {"end", ENDLIST}, ! {".", ENDLIST}, ! {"all", ALL}, ! {"allbits", ALL}, ! {"p", SETPROB}, ! {"P", SETPROB}, ! {"???", BADINPUT}, ! {NULL, NOTFOUND} ! }; ! ! /* Local function prototypes */ ! static void CopyRule(struct BF_fcast *, struct BF_fcast *); ! static void MakePool(struct BF_fcast *); ! static int Tournament(struct BF_fcast *); ! static void Crossover(struct BF_fcast *, int, int, int); ! static BOOL Mutate(int, BOOL); ! static void TransferFcasts(void); ! static void Generalize(struct BF_fcast *); ! static struct BF_fcast *GetMort(struct BF_fcast *); ! static void makebittables(void); ! ! // Local variables, shared by all instances ! static int condbits; /* Often copied from p->condbits */ ! static int condwords; /* Often copied from p->condwords */ ! static int * bitlist; /* Often copied from p->bitlist */ ! static unsigned int * myworld; /* Often copied from p->myworld */ ! static struct BFparams * params; ! static struct BFparams * pp; ! static double avstrength,minstrength; /* working variable for GA */ ! ! ! // Working space, dynamically allocated, shared by all instances ! static struct BF_fcast **reject; /* GA temporary storage */ ! static struct BF_fcast *newfcast; /* GA temporary storage */ ! static unsigned int *newconds; /* GA temporary storage */ ! static int npoolmax = -1; /* size of reject array */ ! static int nnewmax = -1; /* size of newfcast array */ ! static int ncondmax = -1; /* size of newconds array */ ! static int * bits; /* work array during startup */ ! static double * probs; /* work array during startup */ ! extern int ReadBitname(const char *variable, const struct keytable *table); ! ! // PRIVATE METHODS ! @interface BFagent(Private) ! - performGA; ! @end ! ! @implementation BFagent ! ! +(void *)init ! { ! int i, nnulls; ! double currentprob; ! ! //Makes the bit tables for the agent ! makebittables(); ! ! // Allocate space for the bitlists ! bits = calloc(MAXCONDBITS,sizeof(int)); ! if(!bits) ! printf("There was an error allocating space for bits."); ! ! probs = calloc(MAXCONDBITS,sizeof(double)); ! if(!probs) ! printf("There was an error allocating space for probs."); ! ! // Allocate space for our parameters ! params = (struct BFparams *) malloc(sizeof(struct BFparams)); ! if(!params) ! printf("There was an error allocating space for params."); ! ! // Read in general parameters ! params->numfcasts = 60; ! params->tauv = 50.0; ! params->lambda = 0.3; ! params->maxbid = 10.0; ! params->mincount = 5; ! params->subrange = 0.5; ! params->a_min = 0.0; ! params->a_max = 1.98; ! params->b_min = 0; ! params->b_max = 0; ! params->c_min = -10; ! params->c_max = 11.799979; ! params->newfcastvar = 4.000212; ! params->initvar = 4.000212; ! params->bitcost = 0.01; ! params->maxdev = 100; ! params->individual = 0; ! params->bitprob = 0.1; ! ! // Read in the list of bits, storing it in a work array for now ! nnulls = 0; ! currentprob = params->bitprob; ! bits[0] = ReadBitname("pr/d>1/4", specialbits); ! bits[1] = ReadBitname("pr/d>1/2", specialbits); ! bits[2] = ReadBitname("pr/d>3/4", specialbits); ! 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); ! ! for (i=0; i<16; i++) ! { ! probs[i] = currentprob; ! } ! ! ! params->condbits = i; ! params->nnulls = nnulls; ! ! // Allocate permanent space for bit and probability lists, and copy them there ! params->bitlist = calloc(params->condbits,sizeof(int)); ! if(!params->bitlist) ! printf("There was an error allocating space for bitlist."); ! ! params->problist = calloc(params->condbits,sizeof(double)); ! if(!params->problist) ! printf("There was an error allocating space for problist."); ! ! for (i=0; i < params->condbits; i++) ! { ! params->bitlist[i] = bits[i]; ! params->problist[i] = probs[i]; ! } ! ! // Allocate space for our world bits, clear initially ! params->condwords = (params->condbits+15)/16; ! params->myworld = calloc(params->condwords,sizeof(unsigned int)); ! if(!params->myworld) ! printf("There was an error allocating space for myworld."); ! for (i=0; icondwords; i++) ! params->myworld[i] = 0; ! // Check bitcost isn't too negative ! if (1.0+params->bitcost*(params->condbits-params->nnulls) <= 0.0) ! printf("The bitcost is too negative."); - // Read in GA parameters - params->gafrequency = 100; - params->firstgatime = 1000; - params->poolfrac = 0.1; - params->newfrac = 0.05; - params->pcrossover = 0.3; - params->plinear = 0.333; - params->prandom = 0.333; - params->pmutation = 0.01; - params->plong = 0.05; - params->pshort = 0.2; - params->nhood = 0.05; - params->longtime = 2000; - params->genfrac = 0.10; - - // Compute derived parameters - params->gaprob = 1.0/params->gafrequency; - - params->a_range = params->a_max - params->a_min; - params->b_range = params->b_max - params->b_min; - params->c_range = params->c_max - params->c_min; - - params->npool = (int)(params->numfcasts*params->poolfrac + 0.5); - params->nnew = (int)(params->numfcasts*params->newfrac + 0.5); - - // Record maxima needed for GA working space - if (params->npool > npoolmax) npoolmax = params->npool; - if (params->nnew > nnewmax) nnewmax = params->nnew; - if (params->condwords > ncondmax) ncondmax = params->condwords; - - // Miscellaneous initialization - params->lastgatime = 1; - - /* Note that, as well as returning it, the current value of "params" is - * available as a static variable in this file. initAgent: uses that. */ - return (void *)params; - } - - - - static void makebittables() //declared in BFagent.m - /* - * Construct tables for fast bit packing and condition checking for - * classifier systems. Assumes 32 bit words, and storage of 16 ternary - * values (0, 1, or *) per word, with one of the following codings: - * Value Message-board coding Rule coding - * 0 2 1 - * 1 1 2 - * * - 0 - * Thus rule satisfaction can be checked with a simple AND between - * the two types of codings. - * - * Sets up the tables to store MAXCONDBITS ternary values in - * CONDWORDS = ceiling(MAXCONDBITS/16) words. - * - * After calling this routine, given an array declared as - * int array[CONDWORDS]; - * you can do the following: - * - * a. Store "value" (0, 1, 2, using one of the codings above) for bit n with - * array[WORD(n)] |= value << SHIFT[n]; - * if the stored value was previously 0; or - * - * b. Store "value" (0, 1, 2, using one of the codings above) for bit n with - * array[WORD(n)] = (array[WORD(n)] & NMASK[n]) | (value << SHIFT[n]); - * if the initial state is unknown. - * - * c. Store value 0 for bit n with - * array[WORD(n)] &= NMASK[n]; - * - * d. Extract the value of bit n (0, 1, 2, or possibly 3) with - * value = (array[WORD(n)] >> SHIFT[n]) & 3; - * - * e. Test for value 0 for bit n with - * if ((array[WORD(n)] & MASK[n]) == 0) ... - * - * f. Check whether a condition is fulfilled (using the two codings) with - * for (i=0; iname; ptr++) - if (strcmp(variable,ptr->name) == EQ) - break; - if (!ptr->name && strcmp(variable,"???") != EQ) - printf("unknown keyword '%s'\n",variable); - n = ptr->value; - } - return n; - } ! +didInitialize { ! struct BF_fcast *fptr, *topfptr; ! unsigned int *conditions; ! ! // Free working space we're done with ! free(probs); ! free(bits); ! ! // Allocate working space for GA ! reject = calloc(npoolmax,sizeof(struct BF_fcast *)); ! if(!reject) ! printf("There was an error allocating space for reject."); ! ! newfcast = calloc(nnewmax,sizeof(struct BF_fcast)); ! if(!newfcast) ! printf("There was an error allocating space for newfcast."); ! ! newconds = calloc(ncondmax*nnewmax,sizeof(unsigned int)); ! if(!newconds) ! printf("There was an error allocating space for newconds."); ! ! // Tie up pointers for conditions ! topfptr = newfcast + nnewmax; ! conditions = newconds; ! for (fptr = newfcast; fptr < topfptr; fptr++) ! { ! fptr->conditions = conditions; ! conditions += ncondmax; ! } ! ! return self; } ! ! +prepareForTrading //called at the start of each trading period { ! int i, n; ! int * myRealWorld; ! int nworldbits; ! ! pp = (struct BFparams *)params; ! ! // Make a "myworld" string of bits extracted from the full "realworld" ! // bitstring. ! pp = params; ! condwords = pp->condwords; ! condbits = pp->condbits; ! bitlist = pp->bitlist; ! myworld = pp->myworld; ! for (i = 0; i < condwords; i++) ! myworld[i] = 0; ! nworldbits = [self setNumWorldBits]; ! myRealWorld = calloc(nworldbits, sizeof(int)); ! if(!myRealWorld) ! printf("There was an error allocating space for myRealWorld."); ! [self setRealWorld: myRealWorld]; ! for (i=0; i < condbits; i++) ! { ! if ((n = bitlist[i]) >= 0) ! myworld[WORD(i)] |= myRealWorld[n] << SHIFT[i]; ! } ! ! return self; } ! +(int)lastgatime ! { ! pp = (struct BFparams *)params; ! return pp->lastgatime; ! } +setRealWorld: (int *)array { [worldForAgent getRealWorld: array]; return self; } ! +(int)setNumWorldBits { int numofbits; --- 238,320 ---- #define urand() [uniformDblRand getDoubleWithMin: -1 withMax: 1] #define irand(x) [uniformIntRand getIntegerWithMin: 0 withMax: x-1] ! //Macros for bit manipulation ! //pj: Sometimes I use these for diagnostic checking. ! // #define WORD(bit) (bit>>4) ! // #define MAXCONDBITS 80 ! // #define extractvalue(variable, trit) ((variable[WORD(trit)] >> ((trit%16)*2))&3) ! // #define ifnilgetzero(variable, trit) ((variable[WORD(trit)]& (3<<((trit%16)*2)))) ! // Type of forecasting. WEIGHTED forecasting is untested in its present form. + //pj: bluntly, WEIGHTED does not work and is incomplete #define WEIGHTED 0 ! //static void makebittables(void); //now in BFCast.m ! //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. ! static BFParams * params; ! //pj: other global variables were moved either to the performGA method where they are ! //pj: needed or into the BFParams class, where they are used to create BFParams objects ! //pj: ReadBitname moved to BFParams + // PRIVATE METHODS + @interface BFagent(Private) + - performGA; ! //pj: methods now replace previous functions: ! - (BFCast *) CopyRule:(BFCast *) to From: (BFCast *) from; ! - (void) MakePool: rejects From: (id ) list; ! - (BOOL) Mutate: (BFCast *) new Status: (BOOL) changed; ! - (BFCast *) Crossover:(BFCast *) newForecast Parent1: (BFCast *) parent1 Parent2: (BFCast *) parent2; ! - (void) TransferFcastsFrom: newList To: forecastList Replace: rejects; ! - (BFCast *) GetMort: (BFCast *) new Rejects: (id ) rejects; ! - (void) Generalize: (id) list AvgStrength: (double) avgstrength; ! - (BFCast *) Tournament: (id ) list; ! @end + @implementation BFagent ! +(void) setBFParameterObject: x { ! params=x; } ! +(void) init { ! [BFCast init]; //must pass along init statement to BFCast,then to ! //BitVector from there. ! return; } + //pj: none of this functionality is needed anymore + // +didInitialize + // +prepareForTrading //called at the start of each trading period ! //Don't need a class method here for this. If you need something like ! //it, put it in BFParams. ! //+(int)lastgatime ! // { pp = (struct BFparams *)params; ! // return pp->lastgatime; ! // } + //pj: yikes, pointer usage, be careful. +setRealWorld: (int *)array { [worldForAgent getRealWorld: array]; return self; } ! //pj: superfluous method: never called anymore +(int)setNumWorldBits { int numofbits; *************** *** 474,593 **** return numofbits; } -initForecasts { ! struct BF_fcast *fptr, *topfptr; ! unsigned int *conditions, *cond; ! int word, bit, specificity; ! double *problist; ! double abase, bbase, cbase, asubrange, bsubrange, csubrange; ! double newfcastvar, bitcost; // Initialize our instance variables ! p = params; avspecificity = 0.0; - lactivelist = activelist = NULL; gacount = 0; ! variance = p->initvar; [self getPriceFromWorld]; [self getDividendFromWorld]; global_mean = price + dividend; forecast = lforecast = global_mean; - // Extract some things for rapid use (is this worth it?) - condwords = p->condwords; - condbits = p->condbits; - bitlist = p->bitlist; - problist = p->problist; - newfcastvar = p->newfcastvar; - bitcost = p->bitcost; - - // Allocate memory for forecasts and their conditions - fcast = calloc(p->numfcasts,sizeof(struct BF_fcast)); - if(!fcast) - printf("There was an error allocating space for fcast."); - - conditions = calloc(p->numfcasts*condwords,sizeof(unsigned int)); - if(!conditions) - printf("There was an error allocating space for conditions."); ! // Iniitialize the forecasts ! topfptr = fcast + p->numfcasts; ! for (fptr = fcast; fptr < topfptr; fptr++) ! { ! fptr->forecast = 0.0; ! fptr->lforecast = global_mean; ! fptr->count = 0; ! fptr->lastactive = 1; ! fptr->specificity = 0; ! fptr->next = fptr->lnext = NULL; ! ! /* Allocate space for this forecast's conditions out of total allocation */ ! fptr->conditions = conditions; ! conditions += condwords; ! ! /* Initialise all conditions to don't care */ ! cond = fptr->conditions; ! for (word = 0; word < condwords; word++) ! cond[word] = 0; ! ! /* Add non-zero bits as specified by probabilities */ ! if(fptr!=fcast) /* protect rule 0 */ ! for (bit = 0; bit < condbits; bit++) { ! if (bitlist[bit] < 0) ! cond[WORD(bit)] |= MASK[bit]; /* Set spacing bits to 3 */ ! else if (drand() < problist[bit]){ ! cond[WORD(bit)] |= (irand(2)+1) << SHIFT[bit]; ! ++fptr->specificity; ! } ! } ! fptr->specfactor = 1.0/(1.0 + bitcost*fptr->specificity); ! fptr->variance = newfcastvar; ! fptr->strength = fptr->specfactor/fptr->variance; } /* Compute average specificity */ - specificity = 0; - for (fptr = fcast; fptr < topfptr; fptr++) - specificity += fptr->specificity; - avspecificity = ((double) specificity)/p->numfcasts; ! /* 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. */ ! abase = p->a_min + 0.5*(1.-p->subrange)*p->a_range; ! bbase = p->b_min + 0.5*(1.-p->subrange)*p->b_range; ! cbase = p->c_min + 0.5*(1.-p->subrange)*p->c_range; ! asubrange = p->subrange*p->a_range; ! bsubrange = p->subrange*p->b_range; ! csubrange = p->subrange*p->c_range; ! for (fptr = fcast; fptr < topfptr; fptr++) ! { ! fptr->a = abase + drand()*asubrange; ! fptr->b = bbase + drand()*bsubrange; ! fptr->c = cbase + drand()*csubrange; ! } ! return self; } ! -free { ! free(fcast->conditions); ! free(fcast); ! return [super free]; } -prepareForTrading ! /* * Set up a new active list for this agent's forecasts, and compute the * coefficients pdcoeff and offset in the equation * forecast = pdcoeff*(trialprice+dividend) + offset --- 322,479 ---- return numofbits; } + -createEnd + { + + //pj: container objects + activeList=[List create: [self getZone]]; + oldActiveList=[List create: [self getZone]]; + + + + return [super createEnd]; + } + -initForecasts { ! int sumspecificity = 0; ! ! //pj:new vars ! int i; ! BFCast * aForecast; ! int numfcasts; ! id index; // Initialize our instance variables ! ! //pj: in the future, it may be good to have a separate parameter object for each BFagent. ! //pj: now it makes little sense, so I'm commenting out the creation code here and just setting ! //pj: privateParams equal to the global variable that is passed in. ! // if ((privateParams = ! // [lispAppArchiver getWithZone: [self getZone] key: "bfParams"]) == nil) ! // raiseEvent(InvalidOperation, ! // "Can't find the BFParams parameters"); ! // [privateParams init]; ! ! privateParams= params; ! ! 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; forecast = lforecast = global_mean; ! // Iniitialize 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];//pj: 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; ! } ! ! //pj: creates forecasts with all condition bits are 00 here, "don't care" ! - (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; ! double asubrange = privateParams->subrange*privateParams->a_range; ! double bsubrange = privateParams->subrange*privateParams->b_range; ! double csubrange = privateParams->subrange*privateParams->c_range; ! ! aForecast= [BFCast createBegin: [self getZone]]; ! [aForecast setCondwords: privateParams->condwords]; ! [aForecast setCondbits: privateParams->condbits]; ! [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]; ! return aForecast; } ! -setConditionsRandomly: (BFCast *) fcastObject { ! int bit; ! double *problist; ! int *bitlist; ! ! bitlist = [privateParams getBitListPtr]; ! ! problist = [privateParams getProbListPtr]; ! ! for(bit=0; bit< privateParams->condbits; bit++) ! { ! if (bitlist[bit] < 0) ! { ! [fcastObject setConditionsbit: bit FromZeroTo: 3];//3=11 is a "filler" ! } ! else if (drand() < problist[bit]) ! { ! [fcastObject setConditionsbit: bit FromZeroTo: irand(2)+1]; ! //remember 1 means yes, or binary 01, and 2 means no, or 10 ! [fcastObject incrSpecificity];//I wish this were automatic! ! [fcastObject updateSpecfactor]; ! } ! } ! return self; } -prepareForTrading ! /* * Set up a new active list for this agent's forecasts, and compute the * coefficients pdcoeff and offset in the equation * forecast = pdcoeff*(trialprice+dividend) + offset *************** *** 596,792 **** * for later updates. */ { ! register struct BF_fcast *fptr, *topfptr, **nextptr; ! unsigned int real0 = 0, real1, real2, real3, real4; ! double weight, countsum, forecastvar; int mincount; #if WEIGHTED == 1 static double a, b, c, sum, sumv; #else ! struct BF_fcast *bestfptr; double maxstrength; #endif - topfptr = fcast + p->numfcasts; ! // First the genetic algorithm is run if due currentTime = getCurrentTime( ); ! if (currentTime >= p->firstgatime && drand() < p->gaprob) { [self performGA]; ! // Clear linked list for active rules ! lactivelist = activelist = NULL; } lforecast = forecast; ! // Preserve last active list ! lactivelist = activelist; ! for (fptr = activelist; fptr!=NULL; fptr = fptr->next) { ! fptr->lnext = fptr->next; ! fptr->lforecast = fptr->forecast; } // Main inner loop over forecasters. We set this up separately for each // value of condwords, for speed. It's ugly, but fast. Don't mess with // it! Taking out fptr->conditions will NOT make it faster! The highest // condwords allowed for here sets the maximum number of condition bits // permitted (no matter how large MAXCONDBITS). ! nextptr = &activelist; /* start of linked list */ ! myworld = p->myworld; ! if(!myworld) ! real0 = myworld[0]; ! switch (p->condwords) { case 1: ! for (fptr = fcast; fptr < topfptr; fptr++) { ! if (fptr->conditions[0] & real0) continue; ! *nextptr = fptr; ! nextptr = &fptr->next; } break; case 2: ! real1 = myworld[1]; ! for (fptr = fcast; fptr < topfptr; fptr++) ! { ! if (fptr->conditions[0] & real0) continue; ! if (fptr->conditions[1] & real1) continue; ! *nextptr = fptr; ! nextptr = &fptr->next; } break; case 3: ! real1 = myworld[1]; ! real2 = myworld[2]; ! for (fptr = fcast; fptr < topfptr; fptr++) { ! if (fptr->conditions[0] & real0) continue; ! if (fptr->conditions[1] & real1) continue; ! if (fptr->conditions[2] & real2) continue; ! *nextptr = fptr; ! nextptr = &fptr->next; } break; case 4: ! real1 = myworld[1]; ! real2 = myworld[2]; ! real3 = myworld[3]; ! for (fptr = fcast; fptr < topfptr; fptr++) { ! if (fptr->conditions[0] & real0) continue; ! if (fptr->conditions[1] & real1) continue; ! if (fptr->conditions[2] & real2) continue; ! if (fptr->conditions[3] & real3) continue; ! *nextptr = fptr; ! nextptr = &fptr->next; } break; case 5: ! real1 = myworld[1]; ! real2 = myworld[2]; ! real3 = myworld[3]; ! real4 = myworld[4]; ! for (fptr = fcast; fptr < topfptr; fptr++) { ! if (fptr->conditions[0] & real0) continue; ! if (fptr->conditions[1] & real1) continue; ! if (fptr->conditions[2] & real2) continue; ! if (fptr->conditions[3] & real3) continue; ! if (fptr->conditions[4] & real4) continue; ! *nextptr = fptr; ! nextptr = &fptr->next; } break; #if MAXCONDBITS > 5*16 #error Too many condition bits (MAXCONDBITS) #endif - } - *nextptr = NULL; /* end of linked list */ - #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. ! a = 0.0; ! b = 0.0; ! c = 0.0; ! sumv = 0.0; ! sum = 0.0; ! nactive = 0; ! mincount = p->mincount; ! for (fptr=activelist; fptr!=NULL; fptr=fptr->next) ! { ! fptr->lastactive = t; ! if (++fptr->count >= mincount) ! { ! ++nactive; ! a += fptr->strength*fptr->a; ! b += fptr->strength*fptr->b; ! c += fptr->strength*fptr->c; ! sum += fptr->strength; ! sumv += fptr->variance; ! } ! } ! if (nactive) ! { ! pdcoeff = a/sum; ! offset = (b/sum)*dividend + (c/sum); ! forecastvar = (p->individual? sumv/((double)nactive) :variance); ! } ! #else ! // Now go through the list and find best forecast ! maxstrength = -1e50; ! bestfptr = NULL; ! nactive = 0; ! mincount = p->mincount; ! 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; ! } ! } ! } ! if (nactive) { ! pdcoeff = bestfptr->a; ! offset = bestfptr->b*dividend + bestfptr->c; ! forecastvar = (p->individual? bestfptr->variance :variance); } - #endif - else - { - // No forecast!! - // Use weighted (by count) average of all rules - countsum = 0.0; - pdcoeff = 0.0; - offset = 0.0; - mincount = p->mincount; - for (fptr = fcast; fptr < topfptr; fptr++) - if (fptr->count >= mincount) - { - countsum += weight = (double)fptr->strength; - offset += (fptr->b*dividend + fptr->c)*weight; - pdcoeff += fptr->a*weight; } ! if (countsum > 0.0) ! { ! offset /= countsum; ! pdcoeff /= countsum; } ! else ! offset = global_mean; ! forecastvar = variance; } ! divisor = p->lambda*forecastvar; return self; } --- 482,849 ---- * for later updates. */ { ! //register struct BF_fcast *fptr, *topfptr, **nextptr; ! //unsigned int real0, real1, real2, real3, real4 = 0 ; ! double weight, countsum, forecastvar=0.0; int mincount; + //pj: for getting values from world + BitVector * myworld; + + //for using indexes of forecast objects + 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]; } + //this saves a copy of the agent's last as lforecast. lforecast = forecast; ! myworld = [self collectWorldData: [self getZone] ]; ! ! [self updateActiveList: myworld]; ! ! [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. ! ! 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 ! // Now go through the list and find best forecast ! maxstrength = -1e50; ! //bestfptf=NULL ! bestForecast = nil; ! nactive = 0; ! mincount = getInt(privateParams,"mincount"); ! ! //pj: Kept as example of "homemade list" ! // 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; ! // } ! // } ! // } ! ! 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]; ! ! ! // if (nactive) ! // { ! // pdcoeff = bestfptr->a; ! // offset = bestfptr->b*dividend + bestfptr->c; ! // forecastvar = (privateParams->individual? bestfptr->variance :variance); ! // } ! ! //fprintf(stderr,"nactive = %d pjactive %d activeList getCount is %d\n",nactive,pjactivecount, [activeList getCount]); ! 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!! ! // Use weighted (by count) average of all rules ! countsum = 0.0; ! pdcoeff = 0.0; ! offset = 0.0; ! mincount = getInt(privateParams,"mincount"); ! ! ! index=[ fcastList begin: [self getZone]]; ! for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] ) ! { ! if ([aForecast getCnt] >= mincount) ! { ! countsum += weight = [aForecast getStrength]; ! offset += ([aForecast getBval]*dividend + [aForecast getCval])*weight; ! pdcoeff += [aForecast getAval]*weight; ! } ! ! if (countsum > 0.0) ! { ! offset /= countsum; ! pdcoeff /= countsum; ! } ! else ! { ! offset = global_mean; ! } ! forecastvar = variance; ! } ! [index drop]; ! } ! ! divisor = getDouble(privateParams,"lambda")*forecastvar; ! ! return self; ! } ! ! ! -(BitVector *) collectWorldData: aZone; ! { ! int i,n,nworldbits; ! BitVector * world; ! int * bitlist; ! int * myRealWorld=NULL; ! ! ! world= [BitVector createBegin: aZone]; ! [world setCondwords: params->condwords]; ! [world setCondbits: params->condbits]; ! world=[world createEnd]; ! ! bitlist = [params getBitListPtr]; ! nworldbits = [worldForAgent getNumWorldBits]; ! ! myRealWorld = [aZone alloc: nworldbits*sizeof(int)]; ! ! [worldForAgent getRealWorld: myRealWorld]; ! ! 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]]; } + [aZone free: myRealWorld]; + + return world; + } + + + //pj: here is the comment from BFagent about the next thing. // Main inner loop over forecasters. We set this up separately for each // value of condwords, for speed. It's ugly, but fast. Don't mess with // it! Taking out fptr->conditions will NOT make it faster! The highest // condwords allowed for here sets the maximum number of condition bits // permitted (no matter how large MAXCONDBITS). ! ! -updateActiveList: (BitVector *) worldvalues ! { ! 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 ! // 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. Its so much cuter. ! I write it before I understood the fact that the World gives back 10 for yes and agent has 01 for yes. ! ! 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; } *************** *** 805,825 **** -(double)getDemandAndSlope: (double *)slope forPrice: (double)trialprice ! /* * Returns the agent's requested bid (if >0) or offer (if <0) using ! * best (or mean) linear forecast chosen by -prepareForTrading. */ { ! // The actual forecast is given by ! // forecast = pdcoeff*(trialprice+dividend) + offset ! // where pdcoeff and offset are set by -prepareForTrading. forecast = (trialprice + dividend)*pdcoeff + offset; ! // A risk aversion computation now gives a target holding, and its ! // derivative ("slope") with respect to price. The slope is calculated ! // as the linear approximated response of a change in price on the traders' ! // demand at time t, based on the change in the forecast according to the ! // currently active linear rule. if (forecast >= 0.0) { demand = -((trialprice*intratep1 - forecast)/divisor + position); --- 862,882 ---- -(double)getDemandAndSlope: (double *)slope forPrice: (double)trialprice ! /* * Returns the agent's requested bid (if >0) or offer (if <0) using ! * best (or mean) linear forecast chosen by -prepareForTrading */ { ! // The actual forecast is given by ! // forecast = pdcoeff*(trialprice+dividend) + offset ! // where pdcoeff and offset are set by -prepareForTrading. forecast = (trialprice + dividend)*pdcoeff + offset; ! // A risk aversion computation now gives a target holding, and its ! // derivative ("slope") with respect to price. The slope is calculated ! // as the linear approximated response of a change in price on the traders' ! // demand at time t, based on the change in the forecast according to the ! // currently active linear rule. if (forecast >= 0.0) { demand = -((trialprice*intratep1 - forecast)/divisor + position); *************** *** 832,848 **** *slope = -intratep1/divisor; } ! // Clip bid or offer at "maxbid". This is done to avoid problems when ! // the variance of the forecast becomes very small, thought it's not clear ! // that this is the best solution. ! if (demand > p->maxbid) { ! demand = p->maxbid; *slope = 0.0; } ! else if (demand < -p->maxbid) { ! demand = -p->maxbid; *slope = 0.0; } --- 889,905 ---- *slope = -intratep1/divisor; } ! // Clip bid or offer at "maxbid". This is done to avoid problems when ! // the variance of the forecast becomes very small, thought it's not clear ! // that this is the best solution. ! if (demand > privateParams->maxbid) { ! demand = privateParams->maxbid; *slope = 0.0; } ! else if (demand < -privateParams->maxbid) { ! demand = -privateParams->maxbid; *slope = 0.0; } *************** *** 859,878 **** -updatePerformance { ! register struct BF_fcast *fptr; double deviation, ftarget, tauv, a, b, c, av, bv, maxdev; ! // Now update all the forecasts that were active in the previous period, ! // since now we know how they performed. ! // Precompute things for speed ! tauv = p->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/100.; bv = 1.0-av; /* fixed variance if tauv at max */ --- 916,937 ---- -updatePerformance { ! //pj: register struct BF_fcast *fptr; ! BFCast * aForecast; ! id index = nil; double deviation, ftarget, tauv, a, b, c, av, bv, maxdev; ! // Now update all the forecasts that were active in the previous period, ! // since now we know how they performed. ! // 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 */ *************** *** 883,931 **** av = 0.0; bv = 1.0; } ! maxdev = p->maxdev; // Update global mean (p+d) and our variance [self getPriceFromWorld]; ftarget = price + dividend; 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 = p->initvar; else variance = bv*variance + av*deviation*deviation; ! // 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; } ! // NOTE: On exit, fptr->forecast is only guaranteed to be valid for ! // forcasters which matched. The inspector has to calculate the rest ! // itself if it wants to show them all. This is for speed. return self; } --- 942,1034 ---- 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] ) ! { ! double lastForecast; ! lastForecast=[aForecast getLforecast]; ! 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]]; //based on bfagent.m ! // original bfagent has this: ! // rptr->strength = p->maxdev - rptr->variance + rptr->specfactor; ! // BFagent had this: fptr->strength = fptr->specfactor/fptr->variance; } ! [index drop]; ! } ! // NOTE: On exit, fptr->forecast is only guaranteed to be valid for ! // forcasters which matched. The inspector has to calculate the rest ! // itself if it wants to show them all. This is for speed. return self; } *************** *** 944,956 **** -(int)nbits { ! return p->condbits; } -(int)nrules { ! return p->numfcasts; } --- 1047,1059 ---- -(int)nbits { ! return privateParams->condbits; } -(int)nrules { ! return privateParams->numfcasts; } *************** *** 960,975 **** } -(int)bitDistribution: (int *(*)[4])countptr cumulative: (BOOL)cum { ! struct BF_fcast *fptr, *topfptr; unsigned int *agntcond; int i; static int *count[4]; // Dynamically allocated 2-d array static int countsize = -1; // Current size/4 of count[] static int prevsize = -1; ! condbits = p->condbits; if (cum && condbits != prevsize) printf("There is an error with an agent's condbits."); --- 1063,1082 ---- } + //pj: Never gets called. ???? -(int)bitDistribution: (int *(*)[4])countptr cumulative: (BOOL)cum { ! BFCast * aForecast; unsigned int *agntcond; int i; + int condbits; + id index; + static int *count[4]; // Dynamically allocated 2-d array static int countsize = -1; // Current size/4 of count[] static int prevsize = -1; ! condbits = getInt (privateParams, "condbits"); if (cum && condbits != prevsize) printf("There is an error with an agent's condbits."); *************** *** 997,1045 **** for(i=0;inumfcasts; ! for (fptr = fcast; fptr < topfptr; fptr++) { ! agntcond = fptr->conditions; for (i = 0; i < condbits; i++) ! count[(int)((agntcond[WORD(i)]>>SHIFT[i])&3)][i]++; } return condbits; } -(int)fMoments: (double *)moment cumulative: (BOOL)cum { ! struct BF_fcast *fptr, *topfptr; int i; ! condbits = p->condbits; if (!cum) for(i=0;i<6;i++) moment[i] = 0; ! topfptr = fcast + p->numfcasts; ! for (fptr = fcast; fptr < topfptr; fptr++) { ! moment[0] += fptr->a; ! moment[1] += fptr->a*fptr->a; ! moment[2] += fptr->b; ! moment[3] += fptr->b*fptr->b; ! moment[4] += fptr->c; ! moment[5] += fptr->c*fptr->c; } ! ! return p->numfcasts; } ! -(const char *)descriptionOfBit: (int)bit { ! if (bit < 0 || bit > p->condbits) return "(Invalid condition bit)"; else ! return [World descriptionOfBit:p->bitlist[bit]]; } --- 1104,1166 ---- 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 -(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 -(const char *)descriptionOfBit: (int)bit { ! if (bit < 0 || bit > getInt(privateParams,"condbits")) return "(Invalid condition bit)"; else ! return [World descriptionOfBit:privateParams->bitlist[bit]]; } *************** *** 1081,1360 **** // nhood -- size of neighborhood. // longtime -- generalize if rule unused for this length of time // genfrac -- fraction of 0/1 bits to make don't-care when generalising - performGA { ! register struct BF_fcast *fptr; ! struct BF_fcast *nr; register int f; ! int specificity, new, parent1, parent2; ! BOOL changed; double ava,avb,avc,sumc; ++gacount; currentTime = getCurrentTime(); - p->lastgatime = lastgatime = currentTime; ! /* Make instance variable visible to GA routines */ ! pp = p; ! condwords = p->condwords; ! condbits = p->condbits; ! bitlist = p->bitlist; - // Find the npool weakest rules, for later use in TrnasferFcasts - MakePool(fcast); ! // Compute average strength (for assignment to new rules) avstrength = ava = avb = avc = sumc = 0.0; minstrength = 1.0e20; ! for (f=0; f < p->numfcasts; f++) { ! avstrength += fcast[f].strength; ! sumc += 1./fcast[f].variance; ! ava += fcast[f].a * 1./fcast[f].variance; ! avb += fcast[f].b * 1./fcast[f].variance; ! avc += fcast[f].c * 1./fcast[f].variance; ! if(fcast[f].strengthnumfcasts; // Loop to construct nnew new rules ! for (new = 0; new < p->nnew; new++) { ! changed = NO; // Loop used if we force diversity do { // Pick first parent using touranment selection do ! parent1 = Tournament(fcast); ! while (parent1 == 0); // Perhaps pick second parent and do crossover; otherwise just copy ! if (drand() < p->pcrossover) { do ! parent2 = Tournament(fcast); ! while (parent2 == parent1 || parent2 == 0) ; ! Crossover(fcast, new, parent1, parent2); changed = YES; } else ! CopyRule(&newfcast[new],&fcast[parent1]); ! ! // Mutate the result ! if (Mutate(new,changed)) changed = YES; ! // Set strength and lastactive if it's really new ! if (changed) { ! nr = newfcast + new; ! nr->strength = avstrength; ! nr->variance = nr->specfactor/nr->strength; ! nr->lastactive = currentTime; } } while (0); /* Replace while(0) with while(!changed) to force diversity */ } ! // Replace nnew of the weakest old rules by the new ones ! TransferFcasts(); // Generalize any rules that haven't been used for a long time ! Generalize(fcast); ! // Compute average specificity ! specificity = 0; ! for (f = 0; f < p->numfcasts; f++) { ! fptr = fcast + f; ! specificity += fptr->specificity; } ! avspecificity = ((double) specificity)/p->numfcasts; return self; } /*------------------------------------------------------*/ /* CopyRule */ /*------------------------------------------------------*/ ! static void CopyRule(struct BF_fcast *to, struct BF_fcast *from) { - unsigned int *conditions; - int i; ! conditions = to->conditions; // save pointer to conditions ! *to = *from; // copy whole fcast structure ! to->conditions = conditions; // restore pointer to conditions ! for (i=0; iconditions[i]; // copy actual conditions ! if(from->count==0) ! to->strength = minstrength; } /*------------------------------------------------------*/ /* MakePool */ /*------------------------------------------------------*/ ! static void MakePool(struct BF_fcast *fcast) { - register int j, top; - register struct BF_fcast *fptr, *topfptr; ! // Dumb bubble sort ! topfptr = fcast + pp->npool; top = -1; ! for (fptr = fcast; fptr < topfptr; fptr++) { ! for (j = top; j >= 0 && fptr->strength < reject[j]->strength; j--) ! reject[j+1] = reject[j]; ! reject[j+1] = fptr; top++; } ! topfptr = fcast + pp->numfcasts; ! for (; fptr < topfptr; fptr++) { ! if (fptr->strength < reject[top]->strength) ! { ! for (j = top-1; j>=0 && fptr->strength < reject[j]->strength; j--) ! reject[j+1] = reject[j]; ! reject[j+1] = fptr; } } ! /* protect all don't cares (first) from elimination - bl */ ! for(j=0;jnpool;j++) ! if (reject[j]==fcast) reject[j] = NULL; ! /* Note that reject[npool-1]->strength gives the "dud threshold" */ } /*------------------------------------------------------*/ /* Tournament */ /*------------------------------------------------------*/ ! static int Tournament(struct BF_fcast *fcast) { ! int candidate1 = irand(pp->numfcasts); ! int candidate2; do ! candidate2 = irand(pp->numfcasts); while (candidate2 == candidate1); ! if (fcast[candidate1].strength > fcast[candidate2].strength) return candidate1; else return candidate2; } - /*------------------------------------------------------*/ - /* Crossover */ - /*------------------------------------------------------*/ - static void Crossover(struct BF_fcast *fcast, int new, int parent1, - int parent2) - /* - * On the condition bits, Crossover() uses uniform crossover -- each - * bit is chosen randomly from one parent or the other. - * For the real-valued forecasting parameters, Crossover() does - * one of three things: - * 1. Choose a linear combination of the parents' parameters, - * weighted by strength. - * 2. Choose each parameter randomly from each parent. - * 3. Choose one of the parents' parameters (all from one or all - * from the other). - * Method 1 is chosen with probability plinear, method 2 with - * probability prandom, method 3 with probability 1-plinear-prandom. - */ - { - register int bit; - unsigned int *cond1, *cond2, *newcond; - struct BF_fcast *nr = newfcast + new; - int word, parent, specificity; - double weight1, weight2, choice; - int bitparent; - - /* Uniform crossover of condition bits */ - newcond = nr->conditions; - cond1 = fcast[parent1].conditions; - cond2 = fcast[parent2].conditions; - if(irand(1)==0) - { - for (word = 0; word plinear) - { - /* Crossover method 1 -- linear combination */ - weight1 = fcast[parent1].strength/(fcast[parent1].strength + - fcast[parent2].strength); - weight2 = 1.0-weight1; - nr->a = weight1*fcast[parent1].a + weight2*fcast[parent2].a; - nr->b = weight1*fcast[parent1].b + weight2*fcast[parent2].b; - nr->c = weight1*fcast[parent1].c + weight2*fcast[parent2].c; - } - else if (choice < pp->plinear + pp->prandom) - { - /* Crossover method 2 -- randomly from each parent */ - nr->a = fcast[(irand(2)? parent1: parent2)].a; - nr->b = fcast[(irand(2)? parent1: parent2)].b; - nr->c = fcast[(irand(2)? parent1: parent2)].c; - } - else - { - /* Crossover method 3 -- all from one parent */ - parent = (irand(2)? parent1: parent2); - nr->a = fcast[parent].a; - nr->b = fcast[parent].b; - nr->c = fcast[parent].c; - } - - /* Set miscellanaeous variables (but not lastactive, strength, variance) */ - nr->count = 0; // call it new in any case - specificity = -pp->nnulls; - for (bit = 0; bit < condbits; bit++) - if ((nr->conditions[WORD(bit)]&MASK[bit]) != 0) - specificity++; - nr->specificity = specificity; - nr->specfactor = 1.0/(1.0 + pp->bitcost*nr->specificity); - } /*------------------------------------------------------*/ /* Mutate */ /*------------------------------------------------------*/ ! static BOOL Mutate(int new, BOOL changed) ! /* * For the condition bits, Mutate() looks at each bit with * probability pmutation. If chosen, a bit is changed as follows: * 0 -> * with probability 2/3, 1 with probability 1/3 --- 1202,1487 ---- // nhood -- size of neighborhood. // longtime -- generalize if rule unused for this length of time // genfrac -- fraction of 0/1 bits to make don't-care when generalising + - performGA { ! // register struct BF_fcast *fptr; ! // struct BF_fcast *nr; 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; + //pj: could be only in perforGA, but then would be recreated every time. + id newList = [List create: [self getZone]]; //to collect the new forecasts; + id rejectList = [Array create: [self getZone] setCount: getInt(privateParams,"npoolmax")]; + + + static double avstrength,minstrength; ++gacount; currentTime = getCurrentTime(); ! privateParams->lastgatime= params->lastgatime = lastgatime = currentTime; ! ! bitlist = privateParams->bitlist; ! ! // Find the npool weakest rules, for later use in TrnasferFcasts ! //MakePool(fcastList); ! [self MakePool: rejectList From: fcastList]; ! // Compute average strength (for assignment to new rules) avstrength = ava = avb = avc = sumc = 0.0; minstrength = 1.0e20; ! ! for (f=0; f < privateParams->numfcasts; f++) { ! BFCast * aForecast = [fcastList atOffset: f]; ! double varvalue = 0; ! varvalue= [ aForecast getVariance]; ! meanv += varvalue; ! if ( [aForecast getCnt] > 0) ! { ! if ( varvalue !=0 ) ! { ! avstrength += [ [ fcastList atOffset: f] getStrength]; ! sumc += 1.0/ varvalue ; ! ava += [ aForecast getAval ] / varvalue ; ! avb += [ aForecast getBval ] / varvalue; ! avc += [ aForecast getCval ] / varvalue ; ! } ! if( (temp = [ aForecast getStrength ]) < minstrength) ! minstrength = temp; ! } ! } ! ! meanv = meanv/ privateParams->numfcasts; ! ! for (f=0; f < privateParams->numfcasts; f++) ! { ! madv += fabs( [[fcastList atOffset:f] getVariance] - meanv); ! } ! ! madv = madv/privateParams->numfcasts; ! ! // ava /= sumc; ! // avb /= sumc; ! // avc /= sumc; ! /* * Set rule 0 (always all don't care) to inverse variance weight * of the forecast parameters. A somewhat Bayesian way for selecting * the params for the unconditional forecast. Remember, rule 0 is imune to * all mutations and crossovers. It is the default rule. ! */ ! [[fcastList atOffset: 0] setAval: ava/ sumc ]; ! [[fcastList atOffset: 0] setBval: avb/ sumc ]; ! [[fcastList atOffset: 0] setCval: avc/ sumc ]; + avstrength /= privateParams->numfcasts; // Loop to construct nnew new rules ! for (new = 0; new < privateParams->nnew; new++) { ! BOOL changed; + changed = NO; // Loop used if we force diversity do { + double varvalue, altvarvalue = 999999999; + BFCast * aNewForecast=nil; + + aNewForecast = [ self createNewForecast ]; + [aNewForecast updateSpecfactor]; + [aNewForecast setStrength: avstrength]; + + //BFagent.m had equivalent of: [aNewForecast setVariance: [aNewForecast getSpecfactor]/[aNewForecast getStrength]]; + [aNewForecast setLastactive: currentTime]; + //following bfagent.m: + varvalue = privateParams->maxdev-avstrength+[aNewForecast getSpecfactor]; + if (varvalue < 0 ) raiseEvent(WarningMessage, "varvalue less than zero"); + [aNewForecast setVariance: varvalue]; + altvarvalue = [[fcastList atOffset: 0] getVariance]- madv; + if ( varvalue < altvarvalue ) + { + [aNewForecast setVariance: altvarvalue]; + [aNewForecast setStrength: privateParams->maxdev - altvarvalue + [aNewForecast getSpecfactor]]; + } + [aNewForecast setLastactive: currentTime]; + + [newList addLast: aNewForecast]; //?? were these not initialized in original?// + + //[aNewForecast print]; // 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) ; ! ! // Crossover(aNewForecast,parent1, parent2); ! [self Crossover: aNewForecast Parent1: parent1 Parent2: parent2]; ! if (aNewForecast==nil) {raiseEvent(WarningMessage,"got nil back from crossover");} changed = YES; } else ! { ! //pj: CopyRule(aNewForecast,parent1); ! [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?? + // [aNewForecast print]; } while (0); /* Replace while(0) with while(!changed) to force diversity */ } ! // Replace nnew of the weakest old rules by the new ones ! //pj: TransferFcasts ( newList, fcastList , rejectList); ! ! [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; } + /*------------------------------------------------------*/ /* CopyRule */ /*------------------------------------------------------*/ ! -(BFCast *) CopyRule:(BFCast *) to From: (BFCast *) from { ! double minstrength = 1.0e20; ! [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; } /*------------------------------------------------------*/ /* MakePool */ /*------------------------------------------------------*/ ! -(void) MakePool: rejects From: (id ) list { ! register int top; ! int i,j = 0 ; ! BFCast * aForecast; ! BFCast * aReject; ! 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--) { ! [rejects atOffset: j+1 put: aReject ]; ! } //note j decrements at the end of this loop ! [rejects atOffset: j+1 put: aForecast]; top++; } ! ! for ( ; i < getInt(privateParams,"numfcasts"); i++) ! { ! aForecast=[list atOffset: i]; ! if ( [aForecast getStrength] < [[ rejects atOffset: top] getStrength ] ) ! { ! for ( j = top-1; j >= 0 && (aReject=[rejects atOffset:j]) && [aForecast getStrength] < [aReject getStrength]; j--) ! { ! [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 } + + /*------------------------------------------------------*/ /* 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 return candidate2; } /*------------------------------------------------------*/ /* 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: * 0 -> * with probability 2/3, 1 with probability 1/3 *************** *** 1362,1367 **** --- 1489,1501 ---- * * -> 0 with probability 1/3, 1 with probability 1/3, * unchanged with probability 1/3 * This maintains specificity on average. + *VERY CONFUSING, because the values are actually 0,1, and 2 + CONVERTED LIKE SO + + 0 1 1/3 2 1/3 + 1 0 2/3 2 1/3 + 2 0 2/3 1 1/3 + * * For the forecasting parameters, Mutate() may do one of two things, * independently for each parameter. *************** *** 1379,1414 **** */ { register int bit; - register struct BF_fcast *nr = newfcast + new; - unsigned int *cond, *cond0; double choice, temp; BOOL bitchanged = NO; bitchanged = changed; ! if (pp->pmutation > 0) { ! cond0 = nr->conditions; ! for (bit = 0; bit < condbits; bit++) { if (bitlist[bit] < 0) continue; ! if (drand() < pp->pmutation) { ! cond = cond0 + WORD(bit); ! if (*cond & MASK[bit]) { if (irand(3) > 0) { ! *cond &= NMASK[bit]; ! nr->specificity--; } else ! *cond ^= MASK[bit]; bitchanged = changed = YES; } else if (irand(3) > 0) { ! *cond |= (irand(2)+1) << SHIFT[bit]; ! nr->specificity++; bitchanged = changed = YES; } } --- 1513,1556 ---- */ { register int bit; 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) { ! for (bit = 0; bit < privateParams->condbits; bit++) { 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; } } *************** *** 1417,1512 **** /* mutate p+d coefficient */ choice = drand(); ! if (choice < pp->plong) { /* long jump = uniform distribution between min and max */ ! nr->a = pp->a_min + pp->a_range*drand(); changed = YES; } ! else if (choice < pp->plong + pp->pshort) { /* short jump = uniform within fraction nhood of range */ ! temp = nr->a + pp->a_range*pp->nhood*urand(); ! nr->a = (temp > pp->a_max? pp->a_max: ! (temp < pp->a_min? pp->a_min: temp)); changed = YES; } /* else leave alone */ /* mutate dividend coefficient */ choice = drand(); ! if (choice < pp->plong) { /* long jump = uniform distribution between min and max */ ! nr->b = pp->b_min + pp->b_range*drand(); changed = YES; } ! else if (choice < pp->plong + pp->pshort) { /* short jump = uniform within fraction nhood of range */ ! temp = nr->b + pp->b_range*pp->nhood*urand(); ! nr->b = (temp > pp->b_max? pp->b_max: ! (temp < pp->b_min? pp->b_min: temp)); changed = YES; } /* else leave alone */ /* mutate constant term */ choice = drand(); ! if (choice < pp->plong) { /* long jump = uniform distribution between min and max */ ! nr->c = pp->c_min + pp->c_range*drand(); changed = YES; } ! else if (choice < pp->plong + pp->pshort) { /* short jump = uniform within fraction nhood of range */ ! temp = nr->c + pp->c_range*pp->nhood*urand(); ! nr->c = (temp > pp->c_max? pp->c_max: ! (temp < pp->c_min? pp->c_min: temp)); changed = YES; } /* else leave alone */ ! nr->count = 0; if (changed) { ! nr->specfactor = 1.0/(1.0 + pp->bitcost*nr->specificity); ! nr->count = 0; } - return(changed); } /*------------------------------------------------------*/ ! /* TransferFcasts */ /*------------------------------------------------------*/ ! static void TransferFcasts() { ! register struct BF_fcast *fptr, *nr; ! register int new; ! int nnew; ! nnew = pp->nnew; ! for (new = 0; new < nnew; new++) { ! nr = newfcast + new; ! fptr = GetMort(nr); ! // Copy the whole structure and conditions ! CopyRule(fptr, nr); } } /*------------------------------------------------------*/ /* GetMort */ /*------------------------------------------------------*/ ! static struct BF_fcast *GetMort(struct BF_fcast *nr) ! /* 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 * selection, we pick two candidates at random and choose the one --- 1559,1796 ---- /* 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) { /* short jump = uniform within fraction nhood of range */ ! 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 */ /* mutate dividend coefficient */ choice = drand(); ! if (choice < privateParams->plong) { /* 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) { /* short jump = uniform within fraction nhood of range */ ! 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 */ /* mutate constant term */ choice = drand(); ! if (choice < privateParams->plong) { /* 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) { /* short jump = uniform within fraction nhood of range */ ! 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); } + /*------------------------------------------------------*/ ! /* 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. ! * For the real-valued forecasting parameters, Crossover() does ! * one of three things: ! * 1. Choose a linear combination of the parents' parameters, ! * weighted by strength. ! * 2. Choose each parameter randomly from each parent. ! * 3. Choose one of the parents' parameters (all from one or all ! * from the other). ! * Method 1 is chosen with probability plinear, method 2 with ! * probability prandom, method 3 with probability 1-plinear-prandom. ! */ { ! /* Uniform crossover of condition bits */ ! register int bit; ! // unsigned int *cond1, *cond2, *newcond; ! int word; ! double weight1, weight2, choice; ! ! [newForecast setSpecificity: 0]; ! ! 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]; ! if (value > 0) [newForecast incrSpecificity]; ! } ! else ! { ! int value= [parent2 getConditionsbit: bit]; ! [newForecast setConditionsbit: bit FromZeroTo: value ]; ! if (value > 0) [newForecast incrSpecificity]; ! } ! } ! //pj:???wont those changes automatically show up in newForecast??// ! ! // checked with Blake: this was a remnant, only need first if, as above ! // if(irand(1)==0) ! // { ! // for (word = 0; word 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] ]; ! [ newForecast setCval: weight1*[parent1 getCval] + weight2*[parent2 getCval]] ; ! } ! else if (choice < privateParams->plinear + privateParams->prandom) ! { ! /* Crossover method 2 -- randomly from each parent */ ! if(irand(2)) ! [newForecast setAval: [parent1 getAval]] ; else [newForecast setAval: [parent2 getAval]]; ! if(irand(2)) ! [newForecast setBval: [parent1 getBval]] ; else [newForecast setBval: [parent2 getBval]]; ! if(irand(2)) ! [newForecast setCval: [parent1 getCval]] ; else [newForecast setCval: [parent2 getCval]]; ! } ! else ! { ! /* Crossover method 3 -- all from one parent */ ! if (irand(2)) { ! [newForecast setAval: [parent1 getAval]] ; ! [newForecast setBval: [parent1 getBval]] ; ! [newForecast setCval: [parent1 getCval]] ; ! } ! else ! { ! [newForecast setAval: [parent2 getAval]] ; ! [newForecast setBval: [parent2 getBval]] ; ! [newForecast setCval: [parent2 getCval]] ; ! } ! } ! ! { //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 + { + //register struct BF_fcast *fptr, *nr; + //register int new; + // int nnew; + 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]; + + /// for (new = 0; new < nnew; new++) + // { + // nr = newfcast + new; + // fptr = GetMort(nr); + + // // Copy the whole structure and conditions + // CopyRule(fptr, nr); + // } } + /*------------------------------------------------------*/ /* 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 * selection, we pick two candidates at random and choose the one *************** *** 1514,1546 **** * more diversity. */ { ! register int bit, temp1, temp2, different1, different2; ! struct BF_fcast *fptr; ! unsigned int *cond1, *cond2, *newcond; ! int npool, r1, r2, word, bitmax; ! ! npool = pp->npool; ! ! r1 = irand(npool); ! while ((reject[r1] == NULL)) ! r1 = irand(npool); ! ! r2 = irand(npool); ! while (r1 == r2 || reject[r2] == NULL) ! r2 = irand(npool); ! ! cond1 = reject[r1]->conditions; ! cond2 = reject[r2]->conditions; ! newcond = nr->conditions; different1 = 0; different2 = 0; bitmax = 16; ! for (word = 0; word < condwords; word++) { temp1 = cond1[word] ^ newcond[word]; temp2 = cond2[word] ^ newcond[word]; ! if (word == condwords-1) ! bitmax = ((condbits-1)&15) + 1; for (bit = 0; bit < bitmax; temp1 >>= 2, temp2 >>= 2, bit++) { if (temp1 & 3) --- 1798,1844 ---- * 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; ! for (word = 0; word < privateParams->condwords; word++) { temp1 = cond1[word] ^ newcond[word]; temp2 = cond2[word] ^ newcond[word]; ! if (word == privateParams->condwords-1) ! bitmax = ((privateParams->condbits-1)&15) + 1; for (bit = 0; bit < bitmax; temp1 >>= 2, temp2 >>= 2, bit++) { if (temp1 & 3) *************** *** 1550,1576 **** } } ! /* * 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) { ! fptr = reject[r1]; ! reject[r1] = NULL; } else { ! fptr = reject[r2]; ! reject[r2] = NULL; } ! /* fptr = reject[r1]; reject[r1] = NULL; ! */ ! /* if(reject[r1]->count < reject[r2]->count) { fptr = reject[r1]; reject[r1] = NULL; --- 1848,1874 ---- } } ! /* * 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) { ! aReject = [rejects atOffset: r1]; ! [ rejects atOffset: r1 put: nil] ; } else { ! aReject = [rejects atOffset: r2]; ! [ rejects atOffset: r2 put: nil] ; } ! /* fptr = reject[r1]; reject[r1] = NULL; ! */ ! /* if(reject[r1]->count < reject[r2]->count) { fptr = reject[r1]; reject[r1] = NULL; *************** *** 1579,1637 **** fptr = reject[r2]; reject[r1] = NULL; } ! */ ! return fptr; } /*------------------------------------------------------*/ /* Generalize */ /*------------------------------------------------------*/ ! static void Generalize(struct BF_fcast *fcast) ! /* * 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 BF_fcast *fptr; register int f; int bit, j; BOOL changed; ! int currentTime; currentTime = getCurrentTime(); ! for (f = 0; f < pp->numfcasts; f++) { ! fptr = fcast + f; ! if (currentTime - fptr->lastactive > pp->longtime) { changed = NO; ! j = (int)ceil(fptr->specificity*pp->genfrac); for (;j>0;) { ! bit = irand(condbits); if (bitlist[bit] < 0) continue; ! if ((fptr->conditions[WORD(bit)]&MASK[bit])) { ! fptr->conditions[WORD(bit)] &= NMASK[bit]; ! --fptr->specificity; changed = YES; j--; } } if (changed) { ! fptr->count = 0; ! fptr->lastactive = currentTime; ! fptr->specfactor = 1.0/(1.0 + pp->bitcost*fptr->specificity); ! fptr->variance = fptr->specfactor/avstrength; ! fptr->strength = fptr->specfactor/fptr->variance; } } } } @end --- 1877,1984 ---- fptr = reject[r2]; reject[r1] = NULL; } ! */ ! return aReject; } + /*------------------------------------------------------*/ /* 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) { ! [aForecast setCnt: 0]; ! [aForecast setLastactive: currentTime]; ! [aForecast updateSpecfactor]; ! [aForecast setVariance: [aForecast getSpecfactor] / avgstrength]; ! [aForecast setStrength: [aForecast getSpecfactor]/[aForecast getVariance]]; ! //??????????????????????? ! //??bfagent has: ! /* rptr->specfactor = (condbits - pp->nnulls - rptr->specificity)* ! pp->bitcost; ! medvar = pp->maxdev-medianstrength+rptr->specfactor; ! if (medvar >= 0.0) ! rptr->variance = medvar; ! rptr->strength = medianstrength;*/ ! ! } } } + } + + + //pj: in case you want to see the 0101 representation of an integer: + - printcond: (int) word + { + int i; + int n = sizeof(int) * CHAR_BIT; + int mask = 1 << (n-1); + int input=word; + + for ( i=1; i <= n; ++i) + { + putchar(((input & mask) == 0) ? '0' : '1'); + input <<= 1; + if (i % CHAR_BIT == 0 && i < n) + putchar(' '); + } + return self; + } + + - copyList: list To: outputList + { + id index, anObject; + + [outputList removeAll]; + index = [ list begin: [self getZone] ]; + for( anObject = [index next]; [index getLoc]==Member; anObject=[index next] ) + { + [outputList addLast: anObject]; } + [index drop]; + return self; } + @end diff -cb --unidirectional-new-file ASM-20000507/BitVector.h ASM-20000602/BitVector.h *** ASM-20000507/BitVector.h Wed Dec 31 18:00:00 1969 --- ASM-20000602/BitVector.h Fri Jun 2 11:03:37 2000 *************** *** 0 **** --- 1,43 ---- + #import + + @interface BitVector: SwarmObject + { + unsigned int *conditions; + int condwords; + int condbits; + } + + + - createEnd; + + + init; + + -(void) setCondwords: (int) x; + + -(void) setCondbits: (int) x; + + -(void) setConditions: (int *) x; + + -(int *) getConditions; + + -(void) setConditionsWord: (int) i To: (int) value; + + -(int) getConditionsWord: (int) x; + + -(void) setConditionsbit: (int) bit To: (int) x; + + -(int) getConditionsbit: (int)bit; + + -(void) setConditionsbitToThree: (int) bit; + + -(void) switchConditionsbit: (int) bit; + + -(void) setConditionsbit: (int) bit FromZeroTo: (int) x; + + -(void) maskConditionsbit: (int) bit; + + - (void) drop; + + - printcond: (int) word; + + @end diff -cb --unidirectional-new-file ASM-20000507/BitVector.m ASM-20000602/BitVector.m *** ASM-20000507/BitVector.m Wed Dec 31 18:00:00 1969 --- ASM-20000602/BitVector.m Fri Jun 2 11:03:37 2000 *************** *** 0 **** --- 1,187 ---- + #import "BitVector.h" + #import //for limits.h in print method + + //needed for bit math. same as in BFAgent was. + + #define WORD(bit) (bit>>4) + #define MAXCONDBITS 80 + + + static int SHIFT[MAXCONDBITS]; + static unsigned int MASK[MAXCONDBITS]; + static unsigned int NMASK[MAXCONDBITS]; + + static void makebittables(void); + + @implementation BitVector + + - 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> SHIFT[bit]) &3; + return value; + } + + -(void) setConditionsbitToThree: (int) bit + { + conditions[WORD(bit)] |= MASK[bit]; + } + + + -(void) maskConditionsbit: (int) bit + { + conditions[WORD(bit)] &= NMASK[bit]; + // specificity --; + } + + -(void) switchConditionsbit: (int) bit + { + conditions[WORD(bit)] ^= MASK[bit]; + } + + + - (void) drop + { + [[self getZone] freeBlock: conditions blockSize: condwords*sizeof(unsigned int) ]; + [super drop]; + } + + + - printcond: (int) word + { + int i; + int n = sizeof(int) * CHAR_BIT; + int mask = 1 << (n-1); + int input=conditions[word]; + + + for ( i=1; i <= n; ++i) + { + putchar(((input & mask) == 0) ? '0' : '1'); + input <<= 1; + if (i % CHAR_BIT == 0 && i < n) + putchar(' '); + } + return self; + } + + + + static void makebittables() //declared in BFagent.m + /* + * Construct tables for fast bit packing and condition checking for + * classifier systems. Assumes 32 bit words, and storage of 16 ternary + * values (0, 1, or *) per word, with one of the following codings: + * Value Message-board coding Rule coding + * 0 2 1 + * 1 1 2 + * * - 0 + * Thus rule satisfaction can be checked with a simple AND between + * the two types of codings. + * + * Sets up the tables to store MAXCONDBITS ternary values in + * CONDWORDS = ceiling(MAXCONDBITS/16) words. + * + * After calling this routine, given an array declared as + * int array[CONDWORDS]; + * you can do the following: + * + * a. Store "value" (0, 1, 2, using one of the codings above) for bit n with + * array[WORD(n)] |= value << SHIFT[n]; + * if the stored value was previously 0; or + * + * b. Store "value" (0, 1, 2, using one of the codings above) for bit n with + * array[WORD(n)] = (array[WORD(n)] & NMASK[n]) | (value << SHIFT[n]); + * if the initial state is unknown. + * + * c. Store value 0 for bit n with + * array[WORD(n)] &= NMASK[n]; + * + * d. Extract the value of bit n (0, 1, 2, or possibly 3) with + * value = (array[WORD(n)] >> SHIFT[n]) & 3; + * + * e. Test for value 0 for bit n with + * if ((array[WORD(n)] & MASK[n]) == 0) ... + * + * f. Check whether a condition is fulfilled (using the two codings) with + * for (i=0; i ! * ASMModelSwarm.m ([ASMModelSwarm +createBegin:]): This is the first official entry of the Changelog. Before Brandon Weber released the ASM code, I was working against a copy of the code from the SFI's cvs. There are some slight differences, and figuring them out was not too tough. Anyway, the major idea is to get rid of as many "ad hoc" do-it-yourself components, replacing them with off-the-shelf Swarm things. The patch file "ASMpatch1-pj.txt" implements the changes that bring the random number usage "up to date" with Swarm. --- 1,127 ---- + 2000-06-02 Paul Johnson + + * BFagent.h (Agent): Closed memory leaks by [index drop]. Still + some small leak in the GA code. + + 2000-06-01 Paul Johnson + + * BFagent.m : Added BitVector usage, added methods -updateActiveList and + -collectWorldData. + + * BitVector.h,m: Created this class, used in both BFagent.m and BFCast.m. + + 2000-05-31 Paul E. Johnson + + * BFagent.m: Crossover: added calculation of new forecast's + Strength, based on bfagent code. Tried to sort out + mistake/differences between bfagent and BFagent. + + *BFagent.m: moved the "world getting" capability from + +prepareForTrading to -prepareForTrading. Each agent gets its own + copy of the world now. No more need to execute +prepareForTrading + anymore. + + + * BFagent.m: Use "updateSpecfactor" whenever conditions are changed in a + BFCast. + + * BFagent.m: prepareForTrading: commented out previous code to select + activeList on grounds it was false. Instead, created routine to + check forcast's bits, and for each non 00 bit, check if it matches + the world. There's some fat to be removed here, but at least it + is not logically wrong. + + * BFCast.m: added "updateSpecfactor" method. + + + 2000-05-30 Paul Johnson + + * BFagent.m: Found vital flaw in original ASM model--forecasts + were not updated. Dynamics look more persuasive after + fixing. Created "updateForecast" method in BFCast class to do this. + + * BFagent.m (prepareForTrading): lActiveList commented out. It is never used! + + * ASMModelSwarm.m: [BFagent init] no longer needed. + [BFagent didInitialize] no longer needed. + + + * BFagent.m: Note makebittables is now moved to BFCast.m. + "free" method removed, now handled by drop method in BFCast.m + Commented out usage of lActiveList, since it is a memory leak and seems to serve no purpose + + 2000-05-28 Paul E. Johnson + + * BFCast.m: This is a new class that has the same basic structure + as the BF_Cast struct that used to be in BFagent.h. It has + get/set methods for all the variables. Most importantly, is has + the makebittables() function and the bit management + interface/functions. All bit management is handled by methods + like getConditions, getConditionsBit: , setConditions: + setConditionsBit: To:, and so forth. + + * BFagent.m: A complete clarification/reconstruction of the + BFagent code, that eliminates as much as possible any of the + "spaghetti" flavor of the previous BFagent code. + + 1. Separates into 2 new classes the 2 big structs in BFagent.h, + and creates an interface for putting information into BFCasts (the + bit string forecast class) and BFParams ( the parameter keeping + object). The beauty of this is that almost all (99.5%) of the bit + math is moved into that separate class, and the BFagent can change + the values of bits by just telling a forecast object to do it, as + in + + [heyYouForecast setConditionsbit: 22 To: 1]; + + 2. Complete and total elimination of all global variables. + + 3. Replacement of pointer-based "homemade" linked lists with Swarm + Arrays and Lists. This eliminates the need for "hands on" processing + of dynamic memory. + + 4. Conversion of the GA functions into Obj-c methods. They do the + same thing, but don't require all those global declarations. Now + more arguments are passed into these methods so they know which + lists to manipulate without having all those global variables + sitting around. + + 2000-05-25 Paul Johnson + + * BFagent.m: changed IVAR "p" to "privateParams" to ease editing + and clarify things. There is no current purpose in keeping a + private param object, but at some future time it may be useful, + especially if there are subclasses from BFagent. + ([BFagent -performGA]): Everything is as local as possible. + Eliminated all possible global vars. + + 2000-05-25 Paul E. Johnson + + * BFagent.m ([BFagent -performGA]): moved GA functions inside + performGA method, so they have automatic access to Ivars and we no + longer need to declare all those global variables or functions. * + + * BFParams.m: new object to hold parameters, which were previously + kept in a struct. + + 2000-05-24 Paul Johnson + + * BFagent.m: cleared out ^M from Windows + ([BFagent +init]): changed probs and bits from class variables to + local arrays in this method. They are only used in this + method. MAXCONDBITS is a compile-time variable, no need for + dynamic memory. + + 2000-05-07 Paul E. Johnson ! * ASMModelSwarm.m ([ASMModelSwarm +createBegin:]): This is the ! first official entry of the Changelog. Before Brandon Weber ! released the ASM code, I was working against a copy of the code ! from the SFI's cvs. There are some slight differences, and ! figuring them out was not too tough. Anyway, the major idea is to ! get rid of as many "ad hoc" do-it-yourself components, replacing ! them with off-the-shelf Swarm things. The patch file ! "ASMpatch1-pj.txt" implements the changes that bring the random ! number usage "up to date" with Swarm. diff -cb --unidirectional-new-file ASM-20000507/Makefile ASM-20000602/Makefile *** ASM-20000507/Makefile Sun May 7 14:11:44 2000 --- ASM-20000602/Makefile Fri Jun 2 13:01:21 2000 *************** *** 1,27 **** ifeq ($(SWARMHOME),) SWARMHOME=/usr endif ! APPVERSION=2.1 ! BUGADDRESS=weber2@ssc.upenn.edu APPLICATION = asm ! OBJECTS = Agent.o BFagent.o Dividend.o World.o \ Specialist.o Output.o ASMModelSwarm.o \ ! ASMObserverSwarm.o ASMBatchSwarm.o main.o OTHERCLEAN = param.data_* output.data* DATAFILES = batch.setup param.data include $(SWARMHOME)/etc/swarm/Makefile.appl ! main.o: main.m ASMObserverSwarm.h Agent.h BFagent.h Dividend.h World.h \ ! Specialist.h Output.h ASMBatchSwarm.h Agent.o: Agent.h Agent.m ! BFAgent.o: BFagent.h BFagent.m Dividend.o: Dividend.h Dividend.m Output.o: Output.h Output.m ! ASMModelSwarm.o: ASMModelSwarm.h ASMModelSwarm.m Specialist.o: Specialist.h Specialist.m World.o: World.h World.m ! ASMModelSwarm.o: ASMModelSwarm.h ASMModelSwarm.m ASMObserverSwarm.o: ASMObserverSwarm.h ASMObserverSwarm.m ASMBatchSwarm.o: ASMBatchSwarm.h ASMBatchSwarm.m ! --- 1,28 ---- ifeq ($(SWARMHOME),) SWARMHOME=/usr endif ! APPVERSION=2.1.1 ! BUGADDRESS=pauljohn@ukans.edu APPLICATION = asm ! OBJECTS = Agent.o Dividend.o World.o \ Specialist.o Output.o ASMModelSwarm.o \ ! ASMObserverSwarm.o ASMBatchSwarm.o main.o BFParams.o BFCast.o BFagent.o BitVector.o OTHERCLEAN = param.data_* output.data* DATAFILES = batch.setup param.data include $(SWARMHOME)/etc/swarm/Makefile.appl ! 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 ! ASMModelSwarm.o: ASMModelSwarm.h ASMModelSwarm.m BFParams.o Specialist.o: Specialist.h Specialist.m World.o: World.h World.m ! 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 ! BFCast.o: BFCast.h BFCast.m BitVector.h ! BitVector.o: BitVector.h \ No newline at end of file diff -cb --unidirectional-new-file ASM-20000507/README ASM-20000602/README *** ASM-20000507/README Sun May 7 14:11:44 2000 --- ASM-20000602/README Fri Jun 2 11:03:37 2000 *************** *** 1,6 **** ASM-new. note from Paul Johnson April 2, 2000 ! SNAP1: 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 --- 1,6 ---- 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 *************** *** 8,13 **** --- 8,18 ---- random seed, unless you use the command line switch or input a randomSeed of your own. + + 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. -------original readme follows This is the port to Swarm of the original NeXTstep version of diff -cb --unidirectional-new-file ASM-20000507/World.m ASM-20000602/World.m *** ASM-20000507/World.m Sun May 7 14:11:44 2000 --- ASM-20000602/World.m Tue May 30 14:48:08 2000 *************** *** 202,207 **** --- 202,208 ---- {"p100>p500", "price: 100-period MA > 500-period MA"} }; + #define NWORLDBITS (sizeof(bitnamelist)/sizeof(struct bitnamestruct)) #define NULLBIT -1 *************** *** 667,672 **** --- 668,677 ---- @end + + + + diff -cb --unidirectional-new-file ASM-20000507/asm.scm ASM-20000602/asm.scm *** ASM-20000507/asm.scm Wed Dec 31 18:00:00 1969 --- ASM-20000602/asm.scm Wed May 31 14:01:16 2000 *************** *** 0 **** --- 1,46 ---- + (list + + (cons 'bfParams + (make-instance 'BFParams + #:numfcasts 60 + #:tauv 50.0 + #:lambda 0.3 + #:maxbid 10.0 + #:mincount 5 + #:subrange 0.5 + #: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 + #:lastgatime 1 + #:condbits 16 + #:npoolmax -1 + #:nnewmax -1 + #:ncondmax -1 + ))) + + + +