Control perceived equality of distance

[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.
---------------------------------------------------------------------------