|
From: Andy C. <ac...@ll...> - 2003-02-25 02:16:18
|
At 05:50 PM 2/24/2003 -0800, you wrote: >On the subject of "ABM design patterns", this matches one that I have >internally been calling the "Referee" design pattern. The idea in this >pattern is to separate the decision of what agents want to do from the >determination of what actually happens. The "Referee" is an object that >sits between the agents and other agents and the environment that >determines resolution of conflicts if you will. Here, the Landscape seems >to play this role almost exactly, and Mark's reasons for the Landscape >match my own thinking pretty much exactly (I'll leave it to Mark to decide >if resembling my thinking is a good thing or not... ;-) > >A canonical example to me is conservation: if agent A and agent B >simultaneously do something that would result in an exchange of something >between them and that exchange must not violate conservation (e.g. one >gets 20 bucks but the other gives 10 is a bad thing), a referee may be a >nice way to ensure (insure?) conservation. Instead of either A or B >determining unilaterally what they think happens in the transfer, they >"submit their case" to the referee, who then informs them of the results, >thus guaranteeing that they both "see" the same amount being transferred. > >As Mark says, the pattern works well to separate the decision making of >agents from the "resolution" of the physics or other rules of interaction >that the simulation is interested in. I submit that this is one step >towards making agents more interchangeable from simulation to simulation >(IOW, making it more likely that agents created by one team may be plugged >into a simulation created by another): the agents just make decisions, but >the choice of what those decisions actually *do* is encapsulated in the >referee. Within broad limits, agents may be able to function reasonably >well in a variety of different but somewhat related simulations. Oh, I forgot something along the lines of making agents that can be dropped into different simulations... Since there has been discussion of the spaces and in particular generalizing things like "getNeighbors", I thought I'd mention that the Referee pattern is another way to approach this. Instead of having the space itself expose common functionality like GetNeighbor, this could actually be exposed in the Referee. Instead of the agents directly querying the space, it could be argued that essentially they are trying to "see" what is around them; and that the result of that action should be dictated by the Referee. In this pattern, the agents pretty much interact directly only with the Referee. The Referee in turn has access to the other agents, the environment, the space that the agents are interacting with, etc. The Referee could then expose a GetNeighbors function and then choose to implement it as dictated by the conditions of the simulation. The implementation of the Agents doesn't change. Now, there's a sense in which this just pushes the logic for dealing with different underlying spaces from one point in the code to another, but, at least it is in *one* point, the implementation of the Referee, instead of in N points, each of the agents (which, again, ideally could be mixed and matched from different developers, hence more code to change). Perhaps more thought provoking, thinking about "GetNeighbors" more as some sort of "see" function creates scenarios that lend themselves more to the Referee concept. What if there is a "wall" in between you and one of your neighbors? Your simulation might not want you to "see" that neighbor. One way to implement this is to extend the particular space you are working with to include the logic of "walls", but there are a lot of reasons to prefer composition to extension here. I prefer to have the Referee "have a" space as they are currently implemented, and then encode extra logic internally to track these "walls". Again, the Agent implementation doesn't change: it gets some representation of what it "sees" (e.g. a list of other agents), and if one of its physical neighbors isn't included because the Referee determines they don't see it, so be it. Where composition really shines vs extension is in more dynamic situations: say, for example, that the presence of one agent may "block" sight of other agents. Here, the GetNeighbors function in the referee has to encode logic looking at the location of other agents to even compute what the agent sees. To try to get this effect by extension of the spaces is to start having the spaces themselves encode knowledge of simulation specifics like the kinds of agents, etc., which seems fairly obviously to be the wrong path. In general, the Referee is a useful pattern in cases where what an agent *intends* to do does not always happen, or in which the agent cannot unilaterally decide what happens to it because it requires calculations involving interaction with other agents or the environment. Underlying something like "GetMooreNeighborhood" is the assumption that if an agent *wants* to get its neighborhood, it necessarily *can*. Obviously, for many applications, this is fine. But the interesting thing about the Referee is that it doesn't preclude this: one could always have a "no-op" referee in essence, one that allows agents to dictate what they want to do. But by using the pattern, if something comes up where you go "shoot, I don't really want the agents to be able to do that", having the the Referee in place is convenient. Again, if the same development team is writing the simulation *and* the agents, this probably doesn't come up very much. But when you start trying to decouple their implementation to some extent, it becomes more attractive. The Referee can make sure the entities follow the "rules" for this simulation, just in case they were written in a way that might otherwise violate the rules. Cheers, Andy |