[Bruce Abbott (941105.1800 EST)]
Below is ECOLI6. No, it is not yet another "reinforcement" model, nor does
this one "learn." What it does do is implement a two-level perceptual control
system, of all things. The bottom level is basically the Powers/Marken system
regulating the tumble rate as a function of the rate of change in nutrient
levels as sensed by the organism. The top level controls perceived stored
nutrient levels, attempting to keep them near a reference level of 100 units
by setting the gain of the lower-level system. Nutrients are assumed to be
absorbed from the surrounding medium in proportion to their concentration, and
used up in proportion to e. coli's rate of travel. THIS e. coli seeks out
nutrient sources when it is hungry, and avoids them when it is satiated!
E. coli's environment contains two nutrient sources, both 100 units peak
concentration. Nutrients drop off from both sources with the square of the
distance, so pickings are pretty slim around the edges of the screen.
Readouts in the upper right corner of the screen show the gain of the lower-
level system, e. coli's level of stored nutrient, and the nutrient level
around the organism.
I doubt that real e. coli regulate their behavior according to stored nutrient
levels, but who knows? If they did, I'll bet they'd act like this.
Do I get my CSG membership badge and signal ring yet? (:->]
Bruce
{***********************************************************************
* NUTRIENT REGULATION IN E. COLI *
* *
* Programmer: Dr. Bruce B. Abbott *
* Psychological Sciences *
* Indiana U. - Purdue U. *
* Fort Wayne, IN 46805-1499 *
* (219) 481-6399 *
* *
* Created: 11/05/94 *
* *
* This program simulates the "swim and tumble" behavior of e. coli *
* using a two-level perceptual control system. The bottom level *
* regulates change in nutrient levels by altering the rate of *
* tumbling inversely with the rate of change of sensed nutrient. *
* The direction of e. coli's travel after tumbling is random. *
* *
* The second level regulates the gain of the first-level system *
* according to the e. coli's level of stored nutrients relative to *
* a reference level of 100 units. E. coli is assumed to absorb the *
* nutrients around it at a rate proportional to nutrient *
* concentration, and to use up nutrients at a rate proportional to *
* its speed. *
* *
* The environment of e. coli contains two food sources indicated by *
* small rectangles. Nutrient level is 100 at each source, but *
* decreases with the square of the radial distance from each source. *
* Thus, as e. coli wanders away from these sources, the level of *
* nutrient in its vicinity drops off rapidly. *
* *
***********************************************************************}
program Ecoli6;
uses
CRT, Graph, GrUtils;
const
TWOPI = PI * 2;
ENDSESSION = 50000;
var
MaxX, MaxY, Line: integer;
NutrX, NutrY, NutrX2, NutrY2,
X, Y, T, T0, DeltaT, Tmax: integer;
NutMag, NutCon, dNutRef, dNutError, dNut, Gain,
AbsorbRate, LossRate: real;
Fuel, FuelRef: real;
EcoliX, EcoliY,
Speed, Angle: real;
Ch: char;
Clock: longint;
procedure InitScreen;
begin
ClrScr;
InitGraphics;
SetFillStyle(0,0);
MaxX := GetMaxX; MaxY := GetMaxY;
Rectangle(0, 0, MaxX, MaxY);
OutTextXY(MaxX div 2 - 200, Y+5,
'E. COLI SIMULATION: REGULATING STORED NUTRIENTS');
OutTextXY(20, MaxY-75, 'Press ESC to Quit...');
OutTextXY(MaxX-75, Line+20, 'Gain');
OutTextXY(MaxX-75, Line+40, 'Stores');
OutTextXY(MaxX-75, Line+60, 'Nutrient');
end;
procedure ShowReal(x,y: integer; v: real);
var s: string;
begin
str(v:12:2, s);
bar (x,y,x+textwidth(s),y+textheight(s));
outtextxy(x,y,s);
end;
procedure Tumble(var Angle: real);
begin
Angle := TwoPi * Random;
end;
procedure InitSim;
begin
Randomize;
NutrX := MaxX div 3;
NutrY := MaxY div 2;
NutrX2 := MaxX - NutrX;
NutrY2:= NutrY;
EcoliX := 50.0;
EcoliY := 50.0;
X := Round(EcoliX);
Y := Round(EcoliY);
Rectangle(NutrX-2, NutrY-2, NutrX+2, NutrY+2);
Rectangle(NutrX2-2, NutrY2-2, NutrX2+2, NutrY2+2);
Speed := 1.0;
NutMag := 100.0; { max concentration }
dNutRef := 0.00; { Reference rate of change in concentration }
Tmax := 200;
T0 := 5;
T := 0;
Gain := 500.0;
FuelRef := 100;
Fuel := 100;
AbsorbRate := 0.005;
LossRate := 0.2;
repeat Tumble(Angle) until (Angle < PI/2);
Clock := 0;
end;
function NutConcen(X, Y, NutrX, NutrY: real): real;
{ Nutient concentration at point X, Y: environment function }
var
Dist: real;
begin
Dist := Sqrt(Sqr(X - NutrX) + Sqr(Y - NutrY));
NutConcen := NutMag / (1 + 0.001*(Sqr(Dist)));
end;
procedure StepEColi;
var
NewNut: real;
begin
EcoliX := EcoliX + Speed * cos(Angle);
EcoliY := EcoliY + Speed * sin(Angle);
X := Round(EcoliX);
Y := Round(EcoliY);
PutPixel(X, Y, white);
NewNut := NutConcen(EcoliX, EcoliY, NutrX, NutrY)
+ NutConcen(EcoliX, EcoliY, NutrX2, NutrY2);
dNut := NewNut - NutCon;
DeltaT := Round(Gain * (dNutRef - dNut));
T := T + T0 + DeltaT;
if T < 0 then T := 0;
if T > Tmax then
begin
Tumble(Angle);
T := 0;
end;
NutCon := NewNut;
Fuel := Fuel + AbsorbRate*NutCon - LossRate*Speed;
if Fuel < 0 then Fuel := 0 else
if Fuel > 200 then Fuel := 200;
Gain := 50 * (FuelRef - Fuel);
If (Clock mod 10 = 0) then
begin
ShowReal(MaxX-175, Line+20, Gain);
ShowReal(MaxX-175, Line+40, Fuel);
ShowReal(MaxX-175, Line+60, NewNut);
end;
end;
var i: integer;
z: real;
begin
InitScreen;
InitSim;
repeat
inc(Clock);
StepEcoli;
Delay(5);
if Keypressed then Ch := ReadKey;
until (Ch = #27) or (Clock >= ENDSESSION);
if (Ch <> #27) then Ch := ReadKey;
RestoreCRTMode;
CloseGraph;
end.