📄 bfagent.java
字号:
//package asmjava;import swarm.objectbase.SwarmObjectImpl;import swarm.collections.Collection;import swarm.random.NormalDistImpl;import swarm.Globals;import swarm.defobj.Zone;import swarm.objectbase.Swarm;import swarm.objectbase.SwarmImpl;import java.util.LinkedList;public class BFagent extends Agent {// Interface for BFagent -- Classifier predictors//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. public int currentTime; /*"The agent regularly checks with Swarm to see what time it is"*/ public int lastgatime; /*" last time period when the GeneticAlgorithm was run"*/ public double avspecificity; /*'average specificity of active forecasts"*/ public double forecast; /*"prediction of stock price: (trialprice+dividend)*pdcoeff + offset."*/ public double lforecast; /*"lagged forecast: forecast value from previous period"*/ public double global_mean; /*"price+dividend"*/ public double realDeviation; /*" ftarget-lforecast: how far off was the agent's forecast?"*/ public double variance; /*"an Exp.Weighted MA of the agent's historical variance: Combine the old variance with deviation^squared, as in: bv*variance + av*deviation*deviation"*/ public double pdcoeff; /*" coefficient used in predicting stock price, recalculated each period in prepareForTrading"*/ public double offset; /*" coefficient used in predicting stock price, recalculated each period in prepareForTrading"*/ public double divisor; /*" a coefficient used to calculate demand for stock. It is a proportion (lambda) of forecastvar (basically, accuracy of forecasts)"*/ public int gacount; /*" how many times has the Genetic Algorithm been used?"*/ // int nactive; public BFParams privateParams; /*"BFParams object holds parameters of this object"*/ public LinkedList fcastList = new LinkedList(); /*"A Swarm Array, holding the forecasts that the agent might use"*/ public LinkedList activeList = new LinkedList(); /*"A Swarm list containing a subset of all forecasts"*/ public LinkedList oldActiveList = new LinkedList(); /*"A copy of the activeList from the previous time step"*/ public World worldForAgent;// Code for a "bitstring forecaster" (BF) agent/*pj: change comments Nov. 2, 2001.In 2000 comments, I said I was leaving the privateParams object asa shared thing used by all BFagents. Well, I just could not standthat anymore and so now I have the global BFParams object, the onefor which the GUI shows and it is the default for all instances,but now each BFagent gets its own instance of BFParams and it isa copy of BFParams, at least to start. That object privateParamscan now be individualized for each agent. In particular, one thingon the TODO list has to be the individualization of bitlists.Other changes described from last year are all still fine.pj: change comments June 2, 2000I began with the code as released by the ASM research team throughBrandon Weber in April, 2000. Here is a summary of the vital changesthat 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 thismodel. Bit does usually mean something that is 0 or 1, but in thismodel it means something else. In the agent, a bit is what is oftencalled a "trit", something that is valued 00, 01, 10, or 11. Tritmeans smallest thing that can hold three values. In these agents, atrit 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 valueGET READY for the big surprise. In World.m, the coding is reversed, so01 means yes and 10 means no. This accelerates the comparision of theagent's bit vector against the state of the world. Look for the & inthe-updateActiveList: medthod and you'll see why. I've written analternative, more transparent algorithm. I don't think it takes muchmore time, but perhaps your computer will tell differently.2. The bit math got frustrating enough that I have segregated it in aclass I call "BitVector". It is really a vector of "trits" but somuch of the rest of this code uses the term bit that I didn't have theenthusiasm to change it. When a "BitVector" instance is created, ithas to be told how many bits, er trits, of information it is supposedto 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 interfaceallows values to be put in and retrieved in a relatively obvious way.Furthermore, when agents create the "forecast objects" using theBFCast class, then those forecast objects will contain within themBitVector 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 thatwas in BFagent.h. Any bit manipulation that needs to be done can bedone by talking to an instance of that class. The bit manipulation ishidden from this BFagent class, so at some time in the future we couldre-implement BFCast and as long as it had the right interface, theBFagent would not care. The BFCast class talks to the forecast objectthat is inside it and tells it to set bits (er, trits) to certainvalues with messages like "setConditionsbit: 5 To: 2" and BFCast canhandle the rest by passing on the news to the BitVector object.4. The BFParams class now has taken the place of the struct BF_Paramsthat was in BFagent. This change allows some significant upgrades infunctionality. First, the BFParams class uses the SwarmlispAppArchiver. See the initial values in asm.scm. Because theBFParams object contains some variables that are derived from thevalues in the archiver, it is necessary to send an "init" messageafter creating a BFParams object. Second, it is now possible tocustomize the agents by creating a customized BFParams object for eachagent. In the original ASM-2.0 code, there is a "global" variableparams and all agents use that one set of parameters. So far, I notdone much to investigate the advantages of allowing agents to usedifferent numbers of bits (er, trits), but I intend to. Until I dothat, the instance variable "privateParams" simply points to the samesingle BFParams object that is created by ASMModelSwarm, andparameters retrieved from either are thus the same.<Apology mode> Note further, I did not write "get" methods for everyvariable in the BFParams class. It just seemed onerous to do so.There are 2 ways to get values out of BFParams. First, use the ->. Ideclared the IVARS in BFParams to be public, so they can be retrievedwith the symbol -> as if the parameter object were a pointer to astruct, as in: privateParams->condwords. I hate doing that, and havethe 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 forprivate variables, so if you get concerned about declaring all thosepublic IVARS in BFParams, you can get values in this way:getInt(privateParams,"condwords"). I used that a number of times inthis file, but not everywhere, because I got tired of typing.</Apology mode>5. More object orientation. The "homemade" linked lists, built withpointers and other C concepts, are replaced by Swarm collections.Iteration now uses Swarm index objects. Many usages of C alloc andcalloc 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> 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 tobe a class method called +prepareForTrading that would retrieve a copyof all the world's information and pick out what was needed for anagent of this class. Then the result of that calculation would getstored in world. While this had the advantage of doing thecalculation once for all agents of the class, it has the disadvantageof restricting us to having identical bit vectors in all agentforecasts. I've dropped this approach, instead creating a variablemyworld in the agent's -prepareForTrading method, and each agent canlook to the world and get the information it wants.6. Think locally, act locally. Global pointers and lists and anythingelse have been replaced wherever possible by automatic variables(inside methods) or instance variables. I created several new methodsthat 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 whateverarguments are needed, rather than using C functions that access a lotof 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 theforecast objects were different in the original BFagent.m than inthe bfagent.m. Since the bfagent.m file matched the documentationreleased with ASM-2.0, I have changed to use the bfagent.m formulasin this file. Some cleanup can still be made. */BFagent(Zone aZone){ super(aZone);}//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//#define drand() [uniformDblRand getDoubleWithMin: 0 withMax: 1]//#define urand() [uniformDblRand getDoubleWithMin: -1 withMax: 1]//#define irand(x) [uniformIntRand getIntegerWithMin: 0 withMax: x-1]public final double drand(){ return Globals.env.uniformDblRand.getDoubleWithMin$withMax(0,1); }public final double urand(){ return Globals.env.uniformDblRand.getDoubleWithMin$withMax(-1,1); }public int irand(int x){ return Globals.env.uniformIntRand.getIntegerWithMin$withMax(0,x-1); }// Type of forecasting. WEIGHTED forecasting is untested in its// present form.//pj: bluntly, WEIGHTED does not work and is incomplete, It never worked// in ASM-2.0, and that's why it is commented out by setting WEIGHTED to 0.public final double WEIGHTED=0;//pj: this is a static global declaration of the params object, shared by all instances.//pj: note there is also a local copy which is, in current code, intitially the same thing,//pj: and it never changes. The original code had 3 of these, so I'm slimmer by 1/3.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//pj: This is the only global variable I still need, and I'm looking for a way go get rid of it!static double minstrength;// PRIVATE METHODS//@interface BFagent(Private)//pj: methods now replace previous functions://- (BFCast *) CopyRule:(BFCast *) to From: (BFCast *) from;//- (void) MakePool: (id <List>)rejects From: (id <Array>) list;//- (BOOL) Mutate: (BFCast *) new Status: (BOOL) changed;//- (BFCast *) Crossover:(BFCast *) newForecast Parent1: (BFCast *) parent1 Parent2: (BFCast *) parent2;//- (void) TransferFcastsFrom: newList To: forecastList Replace: rejects;//- (BFCast *) GetMort: (BFCast *) new Rejects: (id <List>) rejects;//- (void) : (id) list AvgStrength: (double) avgstrength;//- (BFCast *) Tournament: (id <Array>) list;//@end////@implementation BFagent/*"The BFagent--"bitstring forecasting agent" is the centerpiece ofthe ASM model. The agent competes in a stock market, it buy, itsells. It decides to buy or sell by making predictions about what theprice of the stock is likely to do in future. In order to makepredictions, it keeps a large list of forecast objects on hand, andeach forecast object makes a price prediction. These forecasts, whichare created from the BFCast subclass, are fairly sophisticatedentities, they may monitor many different conditions of the world.The forecast which has the best performance record at any giveninstant is used to predict the future price, which in turn leads tothe buy/sell decision.Inside the file BFagent.m, there is a long set of comments about theupdating that went on in the redesign of this code for ASM-2.2. Inorder to faciliate this revision, several new classes were introduced.BFParams is an object that keeps values of the parameters forBFagents, and BFCast is the forecast object itself. BFCast, in turn,keeps its conditions bits with a subclass called BitVector.If you dig into the code of this agent, you will find a confusingthing, so be warned. This code and articles based on it use the term"bit" to refer to something that can be valued either 0, 1, or 2. 0means "don't care," 1 means "NO" and 2 means "YES". The confusingthing is that it takes two bits to represent this amount ofinformation. In binary, the values would be {00,01,10},respectively. I'm told some people call these trits to keep that inmind that two digits are required. As a result of the fact that ittakes "two bits" to store "one bit's" worth of information, somerelatively complicated book keeping has to be done. That's where allthe parameters like "condbits" and "condwors" come into play. InASM-2.0, that book keeping was all "manually done" right here inBFagent.m, but in the 2.2 version, it is all hidden in the subclassBitVector. So, for purposes of the interface of this class, a bit isa 3 valued piece of information, and values of bits inside forecastsare set by messages to the forecast, like [aForecast setConditionsbit:bit FromZeroTo: 2], for example, will set that bit to 2. If you wantto know if a forecast has YES or NO for a bit x, [aForecastgetConditionsbit: x]. "*//*"This tells BFagents where they should look to get the default parameters. it should give the agent an object from the BFParams class."*/public static void setBFParameterObject(BFParams x){ params=x;}/*"This is vital to set values in the forecast class, BFCast, which in turn initializes BitVector class"*/public static void init(){ BFCast.init(); return;}/*"This creates the container objects activeList and oldActiveList. In addition, it makes sure that any initialization in the createEnd of the super class is done."*//*"initForecasts. Creates BFCast objects (forecasts) and puts them into an array called fCastList. These are the "meat" of this agent's functionality, as they are repeatedly updated, improved, and tested in the remainder of the class. Please note each BFagent has a copy of the default params object called privateParams. It can be used to set individualized values of settings in BFParams for each agent. That would allow true diversity! I don't see how that diversity would be allowed for in the ASM-2.0."*/public Object initForecasts(){ int sumspecificity = 0; int i; BFCast aForecast; int numfcasts;// Initialize our instance variables //all instances of BFagent can use the same BFParams object. //ASM-2.0 was written that way, something like: // privateParams= params; // That seemed fraught with danger, with all instances having // read/write access to a global parameter object, so now I'm // creating a copy that each agent can have and individualize. privateParams = params.copy(getZone()); //If you want to customize privateParams, this is the spot! numfcasts = privateParams.numfcasts; avspecificity = 0.0; gacount = 0; variance = privateParams.initvar; getPriceFromWorld();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -