[From Bill Powers (2004.06.11.0400 MDT)]
To any interested parties.
Appended is the source code for I5.pas, in which each agent controls for
the sophistological perceived equality of spacing to its neighbors, in X
and Y. Typing "d" toggles a constant disturbance of 100 units on and off.
The disturbance acts in the X direction only on the agent located at
coordinates (5,5). The state of the disturbance is indicated on the screen
after it is first turned on. Up to 40 x 40 agents can be plotted.
I have not added code to generate instabilities or to apply disturbances in
the Y direction. Two-dimensional arrays are used.
The control systems have pure integrating output functions. The position of
each agent is the sum of the output variable and the disturbance, if any.
The perceptual input function computes a perceptual signal representing the
difference between the distances to the left and right, or upper and lower,
neighbors. This difference is compared with a reference difference of zero,
and the error is integrated to produce the output.
When the disturbance is turned on, the position of the 5,5 agent jumps to
the right. It then returns toward its proper position as the control
systems adjust their outputs. When the disturbance is turned off, the
position jumps to the left, and returns as the outputa fall back to their
original values.
Best,
Bill P.
···
============================================================================
program I5; { was Index_zm2; { 14 December 2002 }
{was I4 11 June 2004 WTP}
{CONTROLS PERCEIVED EQUALITY OF DISTANCE TO
NEIGHBORS, LEFT-RIGHT AND UP-DOWN.
TYPE D TO TOGGLE X DISTURBANCE OF
POSITION 5,5 ON AND OFF}
uses crt, graph;
const maxrow = 12; { number of entries between borders}
maxcol = 12;
var
PosX,PosY,ox,oy,DiffX,DiffY : array[0..maxcol+1,0..maxrow+1] of real;
Cx, Cy, x, y, x0, y0: integer;
gx, gy, r, p, e, o, d, d0 : real ;
key : char;
Hsize,vsize,i : integer;
Graphmode, Graphdriver: integer;
maxcolor : integer;
s: string;
Procedure InitScreen;
begin
GraphDriver := Detect;
Initgraph(Graphdriver, graphmode,'c:\TP\bgi');
hsize := getmaxx + 1; vsize := getmaxy + 1;
maxcolor := getmaxcolor;
end;
Procedure display;
begin
for x := 1 to maxcol do { Plot circles}
for y := 1 to maxrow do
begin
if (x = 5) and (y = 5) then setcolor(White) else setcolor(Green);
circle(round(Cx + PosX[y,x]),round(Cy + PosY[y,x]),3);
end;
setcolor(lightgray); {Draw connecting lines in y}
for x := 1 to maxcol do
for y := 1 to maxrow do
if y = 1 then moveto(round(Cx + PosX[y,x]),round(Cy + PosY[y,x]))
else lineto(round(Cx + Posx[y,x]),round(Cy + PosY[y,x]));
for y := 1 to maxrow do { Draw connecting lines in x}
for x := 1 to maxcol do
if x = 1 then moveto(round(Cx + PosX[y,x]),round(Cy + PosY[y,x]))
else lineto(round(Cx + Posx[y,x]),round(Cy + PosY[y,x]));
end;
Procedure loop;
begin
r := 0; { ref level for difference in X and Y distance}
for y := 1 to maxrow do
for x := 1 to maxcol do
begin
p := -DiffX[y,x]; {Perceived X difference of distances}
e := (r - p);
ox[y,x] := ox[y,x] + gx*e; {integrating output function}
{Apply position disturbance in X at position 5,5}
if (x = 5) and (y = 5) then d := d0 else d := 0;
PosX[y,x] := ox[y,x] + d; {Add disturbance to position}
p := -DiffY[y,x]; {Perceived Y difference of distances}
e := r - p;
oy[y,x] := oy[y,x] + gy*e;
PosY[y,x] := oy[y,x];
end;
end;
{ In one dimension,
Distance to right neighbor is PosX[x+1] - PosX[x]
Distance to left neighbor is PosX[x] - PosX[x-1]
Difference in distances is (PosX[x+1] - PosX[x]) - (PosX[x] - PosX[x-1])
which reduces to PosX[x+1] - 2*PosX[x] + PosX[x-1].
The perceptual signal represents the difference (inequality) of distances.
NOTE that the matrices go from 0 to max+1 in X and Y, where the first and
last entries are initialized to constants defining the border
of the field (the "chalk marks").
}
Procedure PerceiveDiff;
begin
for x:=1 to maxcol do {do not include borders}
for y := 1 to maxrow do
begin { E is a temporary variable}
DiffX[y,x] := PosX[y,x + 1] - 2*PosX[y,x] + PosX[y,x - 1];
DiffY[y,x] := PosY[y + 1,x] - 2*PosY[y,x] + PosY[y - 1,x];
end;
end;
procedure initprogram;
begin
for y := 0 to maxcol+1 do
begin
PosX[y,0] := -200;
PosX[y,maxcol+1] := 200;
PosY[0,y] := -200;
PosY[maxrow+1,y] := 200;
end;
d0 := 0.0;
key := ' ';
InitScreen;
Cx := 200;
Cy := 200; { defines center of the screen }
{ coefficients for control loops }
gx := 0.2;
gy := 0.2;
x0 := hsize div 2; y0 := vsize div 2+20;
setviewport(x0 - 201, y0 - 201,x0 + 201,y0 + 201,false);
end;
{-----------------------------------------------------------------------}
Begin { Main }
initprogram;
Repeat { Main loop }
PerceiveDiff; { perceive x and y inequalities of distance }
loop; { control loops }
display;
Delay(33);
clearviewport;
if keypressed then key := readkey else key := ' ';
if key in ['d','D'] then
begin { toggle disturbance on and off}
if d0 = 0 then d0 := 100.0 else d0 := 0.0;
setviewport(0,0,hsize-1,20,false);
clearviewport;
moveto(250,0);
outtext('DISTURBANCE');
moveto(350,0);
if d0 > 0.0 then
outtext('_ON') else
outtext('OFF');
setviewport(x0 - 201, y0 - 201,x0 + 201,y0 + 201,false);
end;
until key in ['q','Q'];
closegraph;
end.
---------------------------------------------------------------------------