Creating a new model from scratch: A naive, ground-up tutorial
This tutorial assumes no knowledge of AMP. It is, for the moment, a work in progress, and shows how one naive AMP user navigates through the model creation process. While it is under construction there may be parts that trail off; the AMP developer community will chime in for guidance, and these loose ends will be sewn up, leading to the next challenge.
- Hopefully some of the more confusing aspects that John has heroically struggled through below have been cleared up by the new User Guide. I know that looking at this document was enormously helpful in putting that user guide together. Looking forward to seeing where this example goes and I think it would be extremely useful to have other kinds of example models explored here, both to help other users and to give us an opportunity to see where AMF needs to go to be of maximum benefit to users. --Miles Parker 23:08, 27 April 2010 (UTC)
The model to be created is a simple one. It is based on a forthcoming paper whose primary author is John W. Pepper (University of Arizona), who built on his previous work by taking a suggestion from Robert Axelrod.
The model is intended to demonstrate that positive and negative assortment can occur among populations comprised of two kinds of individuals both of which, regardless of their own type, show a preference for being near members of one type. The situation is analogous to a condition in which one kind of individual causes some form of environmental degradation that impacts itself and others around it.
The model specification is as follows:
N agents exist in space. Agents are of two kinds, traditionally called Cooperators and Defectors. Agents are able to perceive the agents immediately around them within a radius of r units; r is the same for all agents. Agents are able to discern whether these neighbors are C's or D's. If the number of D's around a given agent is greater than the number of C's, the agent will move to a new, randomly selected location (with uniform probability throughout the space).
Parameters in the model:
- N - the number of agents, usually 100
- DF - the 'Defector Fraction', or the proportion of the N agents that are defectors
- r - the radius agents can 'see'
Additionally there are some other variations that will eventually be performed; I'm not sure how AMP will consider these, and whether they are parts of the same 'model' or would be different 'models'. For now the main issue is space; the original formulation, which we can take as a starting point here, is that space is a continuous 1-D ring with periodic boundaries. Agents are located at points along this ring, which is considered to have length 1 (so agent locations are all values between zero [inclusive] and one [exclusive]). There is no restriction on agent collocation: two agents can have the same value for their location, though if the agents are placed randomly this will, presumably, be rare. (There is a version of the original simulation in which agents are placed only at specified intervals (i.e. 0.0, 0.1, 0.2, 0.3) and therefore intentionally occupy the same space; this is to emulate the forerunner of this simulation, which used patches rather than continuous, space.)
This is, in some ways, an unusual ABM- it is not the more common 2D grid. We will see how well AMP can accommodate this unusual (but, arguably, simpler?) kind of space. It should be noted at the outset, however, that visualization will probably be tricky: no visualization strategy for 1D continuous space exists, but for now this is not our immediate concern.
An additional point: all agents assess their neighborhoods simultaneously; then all agents that choose to move on the basis of this assessment move simultaneously. A planned version might allow asynchronous movement, but to match the original simulations, simultaneous movement is the first goal.
Note that there will also be more to be said about what data are collected from this model, but for now the focus will be on getting the model to run.
Step 1: Creating a new project
Assuming you have correctly installed AMP and have Eclipse open, your first step is to create a new project.
Creating a new project is easy, but there's a trick: to do it the easy way you have to be in the right 'Perspective.' Eclipse manages what you see, and what options you have in menus, based on the 'perspective' that you have open. To change perspectives, go to the 'Window' menu and select 'Show Perspective...'. The one you want is 'Agent Modeling'. It may not be listed in the first menu you see; select 'other' and you'll find it in the list (again, if AMP is properly installed). You can also select "Reset Perspective" which will apply the changes for the AMP software, if you've just installed it.
If you are in the "Agent Modeling" perspective, then when you select 'File: New...' one of the menu items is 'Basic MetaABM Project'. Choose that one; you will be asked for a name and a file location- supply whatever you like here. For our tutorial, the project name is 'EvCoOpTutorial'.
Some notes about this: A 'Basic MetaABM Project' allows you to create the model specification. AMP works by taking these specification and automatically generating code to run the model in a specific implementation; the three implementations available are Repast Simphony, AScape, and 'EScape', which runs within the Eclipse environment. Our initial project won't do any of this: for now we are just working on the model specification. Later we'll move it to a specific implementation, where we can see immediate effects of changes to the model specification in the generated code.
Step 2: Creating a .metaabm file for the model's specification
The next step is to create a .metaabm file for the model's specification. Assuming you are still in the 'Agent Modeling' perspective, this is also easy: 'File: New...' allows you to create a new 'MetaABM Model'.
When you do this you are first asked to choose the 'folder' in which to place the new model; choose the folder associated with the project you just created. You are also asked for a name for the file, which we have called evcooptutorial.metaabm. After you enter these and click 'Next' you are confronted with a window that asks you to re-state the package (folder) and file name (I don't know why...?), and then for an 'Implementation Mode', a 'Base Directory', and the kind of XML encoding to be used. Accept the defaults (Implementation Mode is 'Generate' and XML encoding is UTF-8, while 'Base Directory' is blank), even if they are empty, and click 'Finish'.
The file will be created in the folder and opened in the editor. You may also notice that two other subfolders are added: src and doc. The 'doc' folder will already have some contents (html files that describe the components of the model). We will watch as components are added to these automatically.
Step 3: Attributes of the model
The next step is to specify some attributes for the model- these are equivalent to global parameters. For our example, we have three: N, r, and DF (see above).
This is our first look at how the AMP hierarchical editor works.
The editor should initially show the file as the root node in a hierarchical structure that is, at first, collapsed. Expand it by clicking on the little arrow to the left of the file name, and you will see that it contains three child nodes: Acts, Attributes, and Styles.
Right clicking on 'Attributes' gives a large context menu, but the important item is at the top: 'Create Member'. This menu, when selected, offers three options: Attribute, Attribute Array, and State.
This is our first sign of how MetaABM will work. Within the hierarchy each node can have child nodes; however, a node can only have child nodes of certain kinds; each kind of child node, in turn, can have child nodes itself, but, again, only as appropriate. The menus will guide you through what kinds of nodes are available at each point in the hierarchy.
It is also important that you have the 'Properties' window visible somewhere on your screen. If it is not, it can be summoned by 'Window: Show View', though you may, again, have to use the 'Other...' submenu to find it. This should be on by default in the Agent Modeling perspective; "Reset Perspective" will bring it onto the screen if it is not there.
We want to add an 'Attribute' to our 'Attributes' node, so we select 'Attribute'. It is added and initially called 'Attribute'. In the Properties window we can see that its ID is 'attribute' (lower-case), its label is 'Attribute' and its plural label is 'Attributes'. These are all default values; whereas we are keeping the name 'Attributes' for the parent node, we will be assigning names to the individual attributes we create.
We can avoid a temptation here: it might seem that the first attribute should be 'N', the number of agents. However, we will see that AMP provides this parameter automatically at a later stage. Therefore, the first one we will call 'Defector Fraction'. This is done by typing an ID ('Defector Fraction') to replace the word 'attribute' in the ID slot in the Properties window, and the word 'Defector Fraction' to replace the word 'Attribute' in the label' slot in the Properties window. AMP assumes that the plural will be 'Defector Fractions'. Note that all of these are intended to be human-readable; AMP will convert them (i.e. by removing spaces) as needed when code is to be generated.
Further down in the Properties window is 'SType'. I don't know what the 'S' is for (it may be removed in an upcoming release), but this refers to the type of attribute that will be specified. The default is 'Boolean', which is not what we need; choose, from the drop-down options available, 'Real'.
Below this is a slot for 'Default Value'; enter 0.5.
For now we can ignore the other three options available in this node's properties. Optionally we can add a description ('The fraction of agents in the simulation that are Defectors.').
When this has been entered, save the file. Notice that AMP automatically builds some elements that depend on the structure we have entered; in the 'doc' folder, the html documents (you can click on these to open them) will now include the description of the 'Defector Fraction' attribute.
The basic process we used for 'Defector Fraction' can now be repeated for 'Radius'; right-click on the 'Attributes' node to add the member, choosing 'Attribute' and changing its ID, labels, and values as needed. In this case the value will also be of type 'Real', and the default value should be 0.05. Notice that you can overwrite the default plural label 'Radiuss' with the correct 'Radii'.)
Note that these attributes cannot have child nodes; right-clicking on them in the hierarchy doesn't present the user with an option to add a member. This is a property of the kind of node they are ('Attribute' nodes don't have child nodes; however, had you right-clicked on 'Attributes', selected 'Add Member', and chosen 'State' instead of 'Attribute', you would be required to add child nodes; the editor would guide you through this.)
Step 3: Define the Model's Space
The agents in our must exist within some space. Space is a child node of the root node of the hierarchy. Right-clicking on the root node allows us to 'Add a member', which includes the option to add a 'Space' node.
Taking no shortcuts, we will (again in the properties window) change the ID and label of our space to 'ring' and 'Ring' (pl. 'Rings', of course). A description can be added, but the real meat of the matter are the last two options. For 'Border Rule' we need 'Periodic' instead of the default, 'Sticky'. We will also need to change the dimensionality- BUT: before you change it, right-click on the space node (now visible as 'Ring' in the hierarchy'. Notice that you cannot add child nodes. Now return to the Properties window and change the dimensionality to '1'. Once this change is made, two child nodes appear under the 'Ring' node. These represent the dimensions (or, in this case, dimension) of that space.
There is a potential point of confusion here, which will be reconciled in an upcoming release. The 'Dimensions' node is probably vestigial and will be removed- we will ignore it here. Instead focus on the 'Length' node.
Again the editor is a guide: if you increase the Dimensionality of the 'Space' node (try changing it from '1' to '2', you get additional options: with 1 you only get Length, while with 2 you get Width and Height. Try higher dimensions is you like, then return it to '1'.
Return to viewing the properties of 'Length' and change its (S)Type to 'Real'. The default value should be 1.
Step 4: Define the Agents
To define an agent, right-click on the root node in the editor, select 'Create Member' from the context menu, and choose 'Agent'.
Before you do anything else, notice what AMP does for you:
- First, it creates a new agent, which is named based on the name you have for the project. It is a child node of the root; in my case it is called 'evcooptutorial Agent'
- Second, AMP adds a new child node to the 'Attributes' node; this is 'evcooptutorial Agent Count', which, as promised above, is the count of the agents to be created (N).
- Third, it adds a new child node to a section that we haven't yet looked at. One of the child nodes of the root node is 'Acts'; expanding this shows that a pre-packaged action is a set-up action, in my case called 'Build evcooptutorial'. This has always been there (we just haven't looked at it yet). Now it has a child node: 'Create evcooptutorial Agents'.
- Fourth, the new 'agent' under the root node has some child nodes of its own: if you expand your agent node you will see that it has nodes for 'Acts', 'Attributes', and 'Styles', just like the root node.
A quick note about labels: the labels here work just like they did for the examples above, and we could change away from the rather clunky 'evcooptutorial Agent'. However, I'm not going to; the reason is that this model is so abstract that the agents don't _mean_ anything; if an agent was a 'car' or a 'person' or a 'mushroom' or whatever, I would change the label, but they're not- they're just 'agents'. On the other hand, I don't want them to just be 'agents', because if I have several models with abstract agents I don't want them to be confused. So, 'evcooptutorial Agents' it is.
Before we start to define our agents, let's note one other detail. If you select the agent node and look at its properties, you will see that among the properties are a suite of values that allow AMP to look at a specific external Java class to retrieve the agents. The agent could be defined outside of AMP entirely, yet still used here (see See: []). We will not do that for this tutorial, but it is good to know that AMP would allow it.
We need to create one attribute for the agent: whether it is a cooperator or a defector. Right-clicking on 'Attributes' of the agent allows us to create a member, which will be an Attribute. I created an attribute with ID and label, "Defector?". This is a 'Boolean' attribute; true will mean that this agent is one of the bad guys, and false will mean it's one of the good guys.
Our agents will eventually have to be more complicated- they will have to actually do something. For now, however, let's look at how to get them into a running model.
Step 5: Build the Model
The next step- for us- is to get the model to be built.
The procedure here is to fill in the definition for the 'Build evcooptutorial' node, one of the Acts that the root node allows. A child of this is 'Create evcooptutorial Agents'. Selecting the properties for this shows that it already has most of the properties we need, already set to the appropriate defaults:
- Agent- what kind of agent to be created; this is the agent we created above, in my case evcooptutorial Agent.
- Agent Count- this points to the Attribute of the model that was created automatically when we added the agents, evcooptutorial Agent Count.
- For- I don't quite understand this- Miles?
- The idea with this is to specify wether you want to get a single agent back or all agents. But it has never actually been implemented because I think a better way to handle it is using Queries. --Milesparker.gmail.com 05:31, 19 March 2010 (UTC)
- I think the problem, for me, is that I'm not quite sure what it means to 'get a single agent back'; I'm thinking of this procedurally: create N agents. The idea of a 'data flow' doesn't work for me here; perhaps this is related to the comment under the next bullet point. I'm still struggling with the 'data flow' part of AMP, which is one reason why I want to get this tutorial running, because I think this aspect is key. --Jtmurphy.email.arizona.edu 19:05, 19 March 2010 (UTC)
- Selection- Also, I can't quite wrap my head around why this is here, either... it needs a pointer to its parent node, presumably as a target for the 'data flow' aspect?
- You got it! Its not really important here because all the builders are using the same selection. The building is happening from the POV of the parent agent / context. --Milesparker.gmail.com 05:31, 19 March 2010 (UTC)
- Space- here we need to instruct it to put the agents into a space. The space is available in the drop-down box; when clicked, this should reveal 'Ring' as the only option. Select it.
There are also IDs that define this action; I can live with the defaults, which for me are 'createevcooptutorialAgents' and 'Create evcooptutorial Agents'. (Perhaps these should match and both be human-readable, but it doesn't matter.)
Miles: If this is right so far, the next trick is to make it so that there are a set number of Cooperators vs. Defectors. I should note that in the original implementation this was not stochastic, so if N = 100 and DF is .3 there should be exactly 30 defectors, not a 30% of being a Defector for all agents. Is it better to have two kinds of agents? I thought about this a bit- they have different values for the 'Defector?' attribute, but they will have identical 'Acts'...
- Yeah, I don't think it makes sense to have separate types of agents here since it's only the state that is changing. (But sub-classing isn't supported yet anyway.. :)) There are a couple of ways to handle this off the top of my head. First, you can create an attribute in parent that for the defector count, and one for the current number of agents set as defectors. Then, as part of an initialization rule in the Agent, you make agents defectors and increment the current number until you reach the defector count, then when that is zero make them cooperators. Important to set the number back to zero as part of the Parent context's initialization rule so that frameworks that allow model restart will work properly. I forget what the second idea was.. :) It would be nice to have some kind of proportion function at some point that did this automatically. --Milesparker.gmail.com 05:31, 19 March 2010 (UTC)
- What if you make agents defectors until the number of defectors created (and, presumably, placed in the context at that point, so this number should be accessible via a select/query?) is equal to or greater than the product of the Defector Fraction times the Count of EvCoOp Agents (and after that make Cooperators)? In faux Java, "Defector? = (CountOfAllDefectorsInPopulation() >= (DF * N));" This is slower but avoids defining variables/attributes that arguably aren't needed and dodges the restart issue as well. I'll definitely need your guidance on any of these solutions; I don't quite see how the Create Agents act can be made to do this, in terms of what kinds of child nodes should be added to what/where. I can see that the way I am thinking about this is very functional, in the sense of 'functional programming', but I don't know how to translate that into 'data flow' terms. --Jtmurphy.email.arizona.edu 19:04, 19 March 2010 (UTC)
- Yes, I see the confusion. I'm going to work on some docs on that right away. Even form a functional perspective though, the method that you're suggesting above wouldn't be ideal because it involves unnecessarily reiterating over agents that you are in the midst of creating. Really its a two shot deal. At the Super-Scape (parent) level, you're creating the agents. That's a little bit of deus ex machina. :) Then all of the initialize stuff you do within the agents themselves. That's no different then the way that Ascape and Simphony handle this. The confusing part is how many agents are executing where. I think a diagram or two will help and that's what I'm going to work on now.