Programming for Social Scientists
Lecture 8UCLA Political Science 209-1: Programming for Social Scientists
Winter 1999
Lars-Erik Cederman & Benedikt Stefansson
Today’s topics
• More graphics
• Using probes– With GUI– To get and manipulate data
• Probes in action: The Script class
• Overriding methods
Changing the raster graphics
• Want to put a black border around each square on the lattice
• In order to do so must “paint” each tile independently
• Solution: A new message in ObserverSwarm
Raster fromGridIPD
New Raster
Changes in ObserverSwarm.m
• Need to catch the display message from each agent and implement new drawing method
In -buildObjects: worldDisplay = [ModObject2dDisplay createBegin: self]; [worldDisplay setDisplayWidget: (id <Raster>) self];
[worldDisplay setDiscrete2dToDisplay: [modelSwarm getWorld]];
[worldDisplay setObjectCollection: [modelSwarm getPlayers]];
[worldDisplay setDisplayMessage: M(drawSelfOn:)];
[worldDisplay setSizeFactor: sizeFactor];
worldDisplay = [worldDisplay createEnd];
Changes in ObserverSwarm.m (2)
• Agents call the “displayWidget” which is actually the ObserverSwarm and we process the information before calling the raster
-drawPointX: (int) posX Y: (int) posY Color: (int) type {
[worldRaster fillRectangleX0: sizeFactor*posX
Y0: sizeFactor*posY
X1: sizeFactor*(float)(posX+0.9)
Y1: sizeFactor*(float)(posY+0.9)
Color: type];
return self;
}
How it works
Raster
Object2dDisplay
ObserverSwarm
Agent
ObserverSwarm
-drawPointX:Y:Color:-drawPointX:Y:Color:
-fillRectangleX0:Y0:X1:Y1:-fillRectangleX0:Y0:X1:Y1:
-drawSelfOn:-drawSelfOn:
-makeProbeAtX:Y:-makeProbeAtX:Y:
Useful methods in Raster
- fillRectangleX0: (int)x0 Y0: (int)y0 X1: (int)x1 Y1: (int)y1 Color: (Color)color
Fill a rectangle of given geometry and color.
- ellipseX0: (int)x0 Y0: (int)y0 X1: (int)x1 Y1: (int)y1 Width: (unsigned)penWidth Color: (Color)c
Draw an ellipse of given geometry, pen width, and color.
- lineX0: (int)x0 Y0: (int)y0 X1: (int)x1 Y1: (int)y1 Width: (unsigned)penWidth Color: (Color)c
Draw a line of given geometry, pen width, and color.
- rectangleX0: (int)x0 Y0: (int)y0 X1: (int)x1 Y1: (int)y1 Width: (unsigned)penWidth Color: (Color)c
Draw a rectangle of given geometry, pen width, and color.
ModelSwarm
bugList
Graphical probes
ObserverSwarm
Probe Probe
main
ObserverSwarm
How the probes come in...
ModelSwarm
A custom ProbeMapwith 4 MessageProbes
A custom ProbeMapwith 1 MessageProbe
ControlPanel isprovided by kernel
Brief overview of probes
• Two major uses for probes– To interface with an object
– To create a GUI to an object
• Interface with an object of two types– VarProbe: Probes an instance variable
– MessageProbe: Probes a method
• GUI utilities:– ProbeMap: Collection of Var and MessageProbes
Major Probe classes
Probe ProbeMap
CompleteProbeMap
CompleteVarMap
CustomProbeMap
MessageProbe
VarProbe
ObjectBase
ProbeLibrary
Creating graphic probe to object
• Check out instance of EmtpyProbeMap
• Attach VarProbe or MessageProbe to each variable or message to appear on GUI
• Put each probe on ProbeMap
• Ask probeDisplayManager to create actual widget Object
VarProbes
MessageProbeA ProbeMap1
2
3
4
Code for previous exampleprobeMap=[EmptyProbeMap createBegin: aZone];[probeMap setProbedClass: [self class]];probeMap=[probeMap createEnd];[probeMap addProbe: [probeLibrary
getProbeForVariable: ”someVar" inClass: [agent class]]];
...[probeMap addProbe: [probeLibrary getProbeForMessage:
”someVar" inClass: [agent class]] setHideResult: 1]];
[probeLibrary setProbeMap: probeMap For: [self class]];
[probeDisplayManager createProbeDisplayFor: modelSwarm];
Model
Observer
probeMap = [EmptyProbeMap createBegin: self];
[probeMap setProbedClass: [self class]];
probeMap = [probeMap createEnd];
[probeMap addProbe: [probeLibrary
getProbeForVariable: "worldXSize”
inClass: [self class]]]; [probeLibrary setProbeMap: probeMap
For: [self class]];
(also must execute CREATE_PROBE_DISPLAY macro
in ObserverSwarm)
Example: A variable probe
1
2 3
4
probeMap = [EmptyProbeMap createBegin: self];
[probeMap setProbedClass: [self class]];
probeMap = [probeMap createEnd];
[probeMap addProbe: [[probeLibrary
getProbeForMessage: ”setWorldXSize:”
inClass: [self class]]
setHideResult: 1]]; [probeLibrary setProbeMap: probeMap For: [self class]];
(also must execute CREATE_PROBE_DISPLAY macro
in ObserverSwarm)
Example: A message probe
1
2 3
4
A probe for ModelSwarm in IPD+createBegin: (id) aZone {
...
probeMap = [EmptyProbeMap createBegin: aZone];
[probeMap setProbedClass: [self class]];
probeMap = [probeMap createEnd];
[probeMap addProbe: [probeLibrary getProbeForVariable: "randomSeed"
inClass: [self class]]];
[probeMap addProbe: [probeLibrary getProbeForVariable: "worldSize"
inClass: [self class]]];
[probeMap addProbe: [probeLibrary getProbeForVariable: "pALLC"
inClass: [self class]]];
[probeMap addProbe: [probeLibrary getProbeForVariable: "pTFT"
inClass: [self class]]];
[probeMap addProbe: [probeLibrary getProbeForVariable: "pATFT"
inClass: [self class]]];
[probeMap addProbe: [probeLibrary getProbeForVariable: "pALLD"
inClass: [self class]]];
[probeLibrary setProbeMap: probeMap For: [self class]];
...
Code for the ModelSwarm probe
[probeMap addProbe: [probeLibrary getProbeForVariable: "randomSeed" inClass: [self class]]];
[probeMap addProbe: [probeLibrary getProbeForVariable: "worldSize” inClass: [self class]]];
[probeMap addProbe: [probeLibrary getProbeForVariable: "pALLC" inClass: [self class]]];
[probeMap addProbe: [probeLibrary getProbeForVariable: "pTFT"
inClass: [self class]]];
[probeMap addProbe: [probeLibrary getProbeForVariable: "pATFT” inClass: [self class]]];
[probeMap addProbe: [probeLibrary getProbeForVariable: "pALLD" inClass: [self class]]];
Graphical and non-graphical probes
• ProbeMaps are collections of variable and message probes that can be displayed graphically
• Probes can also be used without the graphical component to construct method calls dynamically at runtime
Dynamic message calling
• Probe library allows you to construct method calls dynamically
• Here selector and target are data to be determined at runtime
theProbe=[MessageProbe createBegin: zone];
[theProbe setProbedSelector: theSelector];
theProbe=[theProbe createEnd];
anIndex=[aCollection begin: zone];
while((aMember=[anIndex next])) {
theData=[theProbe doubleDynamicCallOn:aMember]];
[self doSomething: theData];
}
Using probes to collect statistics
• Averager object can probe collection of objects and return average, total, min, max and count
• One use: Use data as argument to printf() statement to collect statistics
Averager
EZGraph
EZBin
Objectbase
Entropy
EZDistribution
Probe
Printing out data using Averager
• Creating:averager =[Averager createBegin: zone];
[averager setCollection: theCollection];
[averager setProbedSelector: theSelector];
averager=[anAverager createEnd];
• Using:[averager update];
printf(“%4.3f %4.3f %4.3f\n”,
[averager getMin],
[averager getAverage],
[averager getMax]);
Scripting with method probes
• Script class reads script file from disk and creates message probes
• Each line of script defines:
access t method arg1 … argN
• Where access is either – method name (get target obj)
– model (target is model)
• Creating a script:script=[Script create: self];
[script setFile: "scriptfile"];
[script logEvents: ”logfile"];
[script buildActions: self];
[script activateIn: self];
• Sample script:# A comment
@begin
model 2 printX:Y: 1 2
model 4 printX:Y: 2 4
# Another comment
model 8 shockMarketTo: -1
getMarket 20 setAlpha: 70
getMarket 30 setAlpha: 50
@end
Example: Scripting the IPD
In ModelSwarm.m:
-activateIn: (id) swarmContext {
[super activateIn: swarmContext];
script=[Script create: self];
[script setScriptFile: "script.txt"];
[script buildActions: self];
[script activateIn: self];
return self;
}
-invadeWithAllD: (int) n {
int i;
id agent,index;
if(n > [playerList getCount])
n=[playerList getCount]-1;
[self shuffle: playerList];
index=[playerList begin: self];
while(i<n && (agent=[index next])){
[agent setPlayerType: 3];
i++;
}
return self;
}
Example:Scripting the IPD (cont)
• Activate ModelSwarm in ObserverSwarm
• Example script triggers an invasion of ALL-D at time step 15 and 20
script.txt
# Comment
@begin
model 15 invadeWithAllD: 100
model 20 invadeWithAllD: 200
@end
The script searches in ModelSwarm for selector
Time step for action