notes-How-To-Add-A-Parameter.txt -------------------------------- Suppose you want to add a new parameter to a model that uses the UM-ExpTools Parameters object. In particular, suppose you have a model in which agents move in a 2D (torus) world randomly, i.e., they just pick one of their 8 neighbor cells and move into it if its empty. A model that does this is in /users/rlr/Courses/ICPSR-02/SimpleModel1 so you could copy that to some directory in your space, e.g, make a directory called SimpleModel1-B and start with that version of the program. Suppose you now want to have some agents have a bias to move to the left. At the Agent level, this could be implemented by having a probMoveLeft instance variable, which the agent first checks to see if its going to move left. (Details on implementing this are below.) Now we could just give every agent a fixed, constant probMoveLeft, but that would leave us with a very inflexible model. A better approach is to be able to control both the fraction of agents who have this bias, and the extent of bias those agents have. Thus one way to obtain that flexibility is to have a (parameterized) fraction of the agents have a (parameterized) bias to move to the left. One way to do this would be to introduce three parameters: parameter name aka meaning ------------------ ---- ------------------------------------- fractionBiasedLeft fbl fraction of agents who have a bias meanProbMoveLeft mpml the mean probability to move left of agents created with a bias. That is, biased agents are given a bias by drawing from a Normal distribution with this mean, and with varProbMoveLeft vpml a variance specified by this parameter. Some reasons to introduce these three parameters include: a. The ability to control the fraction of biased agents means one can "tune" the model so it has no biased agents, to replicate results from the original model. b. The ability to control the shape of the distribution from which each agent's probMoveLeft is drawn means one can create populations with more or less heterogeneity on this characteristic. So...give the above, here are the steps to take to introduce this new parameter. Note it should be done a step at a time, compiling and testing the program at various points along the process. 1. First change the Parameters.h and Parameters.m files. In Parameters.h we: Define the name and type of the parameters by adding instance variables to the Parameters object interface, right after the existing parameters (numAgents, worldXSize, worldYSize): double fractionBiasedLeft; double meanProbMoveLeft; double varProbMoveLeft; We use double variables because we want to store real (decimal) values. For other parameters, we might have used int, unsigned int, and so on. In Parameters.m we: A. In the +createBegin: method, we give the parameters default values, and add them to the probe display. Thus to the lines: obj->numAgents = 20; obj->worldXSize = 10; obj->worldYSize = 10; add these lines like this one: obj->fractionBiasedLeft = 0.0; for all three new parameters---you can set the defaults to whatever you want. Then, just a few lines below that, you will see where the original parameter names are used to set up the probe For each parameter there are two lines, e.g., [probeMap addProbe: [probeLibrary getProbeForVariable: "worldYSize" inClass: [self class]]]; Use the mouse to copy the last 2 lines (with worldYSize) three times, and then just change the names to the new parameter names. B. Now we need to add lines to the initParameters method to tell the model the name, alias and data type of the parameters. Again, you will see sets of (3) lines for each of the existing parameters. Just copy one of those blocks of three lines three times, once for each new parameter. Then change: - the name (after setParName:) - the alias (after Aka:) - the data type (after Type:), to doublePar in this case Now is a good time to save the files, "make" the program, fix any compilation errors, and when ok, test it. At this point you should be able to: - see the parameters names, aliases, and defaults printed with ./sm1 -Dh - set the parameters (via name or alias) on the command line ./sm1 -DfractionBiasedLeft=0.2 -Dmpml=0.3 -Dvpml=0.25 These values should appear in the probe when the model starts, and if you run the model a few steps, you can look in the report file: cat report and see the new parameters and the values you assigned to them. Once the above is working, its also a good time to make save to save a snapshot of the working program. 2. Next let's change the Agent's so they can store the new probMoveLeft instance variable. In Agent.h, Add the instance variable after the others: double probMoveLeft; Also, add the declarations for the accessors to set/get this new instance variable. To do this, just copy another pair of set/get method declarations (for a IV of type double), and just change the name. In Agent.m Just add the definitions of the set/get methods. Again, the easiest way to do it is to copy one of the existing pairs of get/set for some other instance variable (IV), and change the name (and data type, if need be). NB: You have to change both the name in the method (ie in the setX and getY part), but also the name of the instance variable in the body of the method, i.e., in the part in the { }. You could save, compile and even test at this point, too. The test is to run the model, probe an agent, and see that your new instance variable is there (with value=0 most likely). 3. Next we need to use the parameters to store the appropriate probMoveLeft values in the Agents when we create them. In ModelSwarm.m there the agent's are created by the -createAgent method, so that's where we will make our changes. Note the way we can find out what the parameter values are is with the macros to access parameter values, e.g., RetIPar("worldXSize") Note the "I" means integer parameter type. So we will want to change that to "D", eg RetDPar("fractionBiasedLeft") We need to do two things with the parameters: A. Use the fractionBiasedLeft parameter to choose agents to have the bias. We can do this probabilistically by have a conditional test to see which agents we will give a non-zero probMoveLeft. Note we use the same kind of test we use to see if an agent will cooperate or defect based on its y value: if ( RetDPar("fractionBiasedLeft") >= getUniformD(0,1) ) { // create a biased agent. } B. To create a biased agent, we want to send it a setProbMoveLeft: message with the appropriate value. The value for each agent is obtained by sampling from a Normal( meanProbMoveLeft, varProbMoveLeft) distribution. This could be done by adding: [agent setProbMoveLeft: getNormalD( RetDPar("meanProbMoveLeft"), RetDPar("varProbMoveLeft") ) ]; right before the return statement in the createAgent method. However, note there could be a problem: we may get samples that are not in the [0,1] range!! If the same is out of range, we could: - just set it to the boundry. - try again until we get a sample in bounds. Let's do the second by using this macro: getNormalDPRepeatUntilInRange( mean, var, min, max ); where the mean and var are filled in as above, and the min and max are 0.0 and 1.0, of course. (NB: this could lead to a infinite loop if one sets the mean to something like 2.0 and var to 0.0 !! A more robust program would check parameter values to make sure they make sense.) So..after making those changes in ModelSwarm.m, its a good time to save, compile and test. How to test? Again, you can probe a few agents and see if they have probMoveLeft values that seem right for the parameters you enter. Or you could add a DMSG(...) to print values as the agents are created. Or you could print out the probMoveLeft values in the printSelfOn: method in the Agent.m file. Note another thing you could do is color the agents who have a bias differently. Can you see how to do that? The basic way to set the color of an agent is to send it the setAgentColor: message with the integer value of the color to use, using the integer-color mapping defined in ObserverSwarm.m, e.g., with a line like: [agent setAgentColor: 135]; (NB: we have to take this line: [[modelSwarm getAgentList] forEach: M(setAgentColor:) : (void *) 131]; out of ObserverSwarm.m because it tells all the agents to set their colors to 131 *after* ModelSwarm creates the agents.) 4. Now we are finally ready to change the Agent's so that they do have this bias to move left! This again involves making a drawn from a Uniform[0,1] distribution, and comparing it to the agent's probMoveLeft. A good place to do this is in the Agent-step method. The logic we want is: if ( agent-moves-left-this-time ) // move left else [self makeRandomMove]; So the conditional is just like the ones we've seen before when we want to do something some fraction of the time: if ( probMoveLeft >= getUniformD(0,1) ) Now how to move left? Basically we just decrement x by 1. But we also have to check for moving left from the x=0 edge, which we can do by normalize the x value as we do in makeRandomMove: x = (x - 1 + worldXSize) % worldXSize; So...after adding all this, its a good time to make and test. (Testing is easier if you change agent colors...) Finally, you are ready to do experiments, e.g., see if there are differences in the average wealth the agents can accumulate for different distributions of probMoveLeft. -------------------------------------------- You should try to do all the changes above yourself. But if you really get stuck, you can see a program that has these changes added in /users/rlr/Courses/ICPSR-02/SimpleModel1-B You can of course copy that to a directory in your space in the same way you have copied other models. ========================================================================