SIMULATION BEGIN PROCESS CLASS Vehicle2B (id, g, world, x, y, vx, vy); INTEGER id; REF (Genes) g; REF (Environment) world; REAL x, y, vx, vy; BEGIN REAL food_reserves; REF (Sensor) LeftSensor, RightSensor; REF (Motor) LeftMotor, RightMotor; REF (Vehicle2B) PROCEDURE with_food_reserves (f); REAL f; BEGIN food_reserves := f; with_food_reserves :- THIS Vehicle2B END with_food_reserves; REAL PROCEDURE current_mass; BEGIN current_mass := g.frame_mass + food_reserves END current_mass; PROCEDURE inertia (t); REAL t; BEGIN x := x + vx * t; y := y + vy * t; END inertia; PROCEDURE friction (t); REAL t; BEGIN vx := vx * (1 - t/g.friction_time); vy := vy * (1 - t/g.friction_time); END friction; PROCEDURE food_burning (t); REAL t; BEGIN food_reserves := food_reserves - t * g.quiet_burn_rate END food_burning; PROCEDURE any_bouncing; BEGIN IF x < world.xmin THEN BEGIN x := world.xmin; vx := -vx END IF; IF x > world.xmax THEN BEGIN x := world.xmax; vx := -vx END IF; IF y < world.ymin THEN BEGIN y := world.ymin; vy := -vy END IF; IF y > world.ymax THEN BEGIN y := world.ymax; vy := -vy END IF; END any_bouncing; PROCEDURE any_eating; BEGIN REF (food_pellet) p; p :- world.ListOfPellets.FIRST; WHILE p =/= NONE DO BEGIN REF (food_pellet) next; next :- p.SUC; IF p.distance(THIS Vehicle2B.x, THIS Vehicle2B.y) <= g.grasp_distance THEN BEGIN COMMENT eat the pellet; REAL vfactor; COMMENT velocity change on inelastic collision with the pellet; p.OUT; CANCEL(p); vfactor := current_mass / (current_mass + p.mass); vx := vx * vfactor; vy := vy * vfactor; food_reserves := food_reserves + p.mass; OUTTEXT ("*** Vehicle "); OUTINT(id,2); OUTTEXT (" has eaten food pellet "); OUTINT(p.id,5); OUTIMAGE; OUTIMAGE; OUTIMAGE; END IF; p :- next END WHILE END any_eating; PROCEDURE starve; BEGIN OUTTEXT("*** Vehicle "); OUTINT(id,2); OUTTEXT(" has starved to death"); OUTIMAGE; OUTIMAGE; OUTIMAGE; OUT; CANCEL (LeftSensor); CANCEL (RightSensor); CANCEL (LeftMotor); CANCEL (RightMotor); CANCEL (world.m); PASSIVATE END starve; PROCEDURE reproduce; BEGIN OUTTEXT("*** Vehicle "); OUTINT(id,2); OUTTEXT(" reproducing....."); OUTIMAGE; OUTIMAGE; OUTIMAGE; OUT; CANCEL (LeftSensor); CANCEL (RightSensor); CANCEL (LeftMotor); CANCEL (RightMotor); CANCEL (world.m); ACTIVATE NEW Vehicle2B(unique_id(IDSTREAM_V), g.mutated, NEW Environment, x, y, vx, vy) .with_food_reserves (food_reserves/2 - g.frame_mass); ACTIVATE NEW Vehicle2B(unique_id(IDSTREAM_V), g.mutated, NEW Environment, x, y, -vx, -vy) .with_food_reserves (food_reserves/2 - g.frame_mass); PASSIVATE END reproduce; LeftSensor :- NEW Sensor (THIS Vehicle2B); RightSensor :- NEW Sensor (THIS Vehicle2B); LeftMotor :- NEW Motor (THIS Vehicle2B); RightMotor :- NEW Motor (THIS Vehicle2B); LeftSensor .MotorItControls :- RightMotor; RightSensor.MotorItControls :- LeftMotor; INTO (ListOfVehicles); ACTIVATE LeftSensor; ACTIVATE RightSensor; ACTIVATE LeftMotor; ACTIVATE RightMotor; OUTTEXT("********** Vehicle "); OUTINT(id,2); OUTTEXT(" born"); OUTIMAGE; OUTTEXT("Genes:"); OUTIMAGE; OUTIMAGE; INSPECT g DO BEGIN OUTREAL(frame_mass,6,13); OUTTEXT(" frame_mass"); OUTIMAGE; OUTREAL(motor_impulse,6,13); OUTTEXT(" motor_impulse"); OUTIMAGE; OUTREAL(sensor_angle,6,13); OUTTEXT(" sensor_angle"); OUTIMAGE; OUTREAL(motor_angle,6,13); OUTTEXT(" motor_angle"); OUTIMAGE; OUTREAL(motor_burn,6,13); OUTTEXT(" motor_burn"); OUTIMAGE; OUTREAL(grasp_distance,6,13); OUTTEXT(" grasp_distance"); OUTIMAGE; OUTREAL(sensitivity,6,13); OUTTEXT(" sensitivity"); OUTIMAGE; OUTREAL(AxonTravelTime,6,13); OUTTEXT(" AxonTravelTime"); OUTIMAGE; OUTREAL(AbsoluteRefractoryPeriod,6,13); OUTTEXT(" AbsoluteRefractoryPeriod"); OUTIMAGE; OUTREAL(quiet_burn_rate,6,13); OUTTEXT(" quiet_burn_rate"); OUTIMAGE; OUTREAL(friction_time,6,13); OUTTEXT(" friction_time"); OUTIMAGE; OUTIMAGE; OUTREAL(reproduction_demand,6,13); OUTTEXT(" reproduction_demand"); OUTIMAGE; END INSPECT; OUTIMAGE; OUTIMAGE; OUTIMAGE; WHILE food_reserves > 0 AND food_reserves < g.reproduction_demand DO BEGIN REAL tstep; tstep := UNIFORM (tstepmin, tstepmax, SEED); HOLD (tstep); inertia (tstep); friction (tstep); food_burning (tstep); any_bouncing; any_eating; END WHILE; IF food_reserves <= 0 THEN starve; IF food_reserves >= g.reproduction_demand THEN reproduce END Vehicle2B; PROCESS CLASS Sensor (VehicleItsIn); REF (Vehicle2B) VehicleItsIn; BEGIN REF (Motor) MotorItControls; REAL PROCEDURE firing_probability (t); REAL t; BEGIN REAL PROCEDURE angle_dependence (a); REAL a; COMMENT relative sensitivity of sensor for signal entering from various angles, defining sensitivity to head-on signal (a=0) as 1; BEGIN angle_dependence := COS(a) ** 2 END angle_dependence; REAL aka_firing_probability; INSPECT VehicleItsIn DO BEGIN REAL facing_angle; REAL signal_intensity; REF (food_pellet) p; IF THIS Sensor == LeftSensor THEN facing_angle := theta(vx,vy) + g.sensor_angle ELSE facing_angle := theta(vx,vy) - g.sensor_angle; signal_intensity := 0; p :- world.ListOfPellets.FIRST; WHILE p =/= NONE DO BEGIN REAL sensor_entry_angle; sensor_entry_angle := angular_separation (facing_angle, theta (p.x - THIS Vehicle2B.x, p.y - THIS Vehicle2B.y) ); IF ABS (sensor_entry_angle) <= PI/2 THEN BEGIN signal_intensity := signal_intensity + t * g.sensitivity * angle_dependence (sensor_entry_angle) / (p.distance(x,y) + g.grasp_distance) END IF; p :- p.SUC END WHILE; aka_firing_probability := 1 - EXP(-signal_intensity); END INSPECT; firing_probability := aka_firing_probability END firing_probability; WHILE TRUE DO BEGIN REAL tstep; tstep := UNIFORM (tstepmin, tstepmax, SEED); HOLD (tstep); IF DRAW (firing_probability (tstep), SEED) THEN BEGIN ACTIVATE MotorItControls DELAY VehicleItsIn.g.AxonTravelTime; HOLD(VehicleItsIn.g.AbsoluteRefractoryPeriod) END IF END WHILE END Sensor; PROCESS CLASS Motor (VehicleItsIn); REF (Vehicle2B) VehicleItsIn; BEGIN WHILE TRUE DO BEGIN PASSIVATE; INSPECT VehicleItsIn DO BEGIN REAL impulse_angle; REAL ximpulse, yimpulse; IF THIS Motor == LeftMotor THEN impulse_angle := theta(vx,vy) - g.motor_angle ELSE impulse_angle := theta(vx,vy) + g.motor_angle; ximpulse := g.motor_impulse * COS(impulse_angle); yimpulse := g.motor_impulse * SIN(impulse_angle); vx := vx + ximpulse / current_mass; vy := vy + yimpulse / current_mass; food_reserves := food_reserves - g.motor_burn END INSPECT; END WHILE END Motor; CLASS Genes (frame_mass, motor_impulse, sensor_angle, motor_angle, motor_burn, grasp_distance, sensitivity, AxonTravelTime, AbsoluteRefractoryPeriod, quiet_burn_rate, friction_time); REAL frame_mass, motor_impulse, sensor_angle, motor_angle, motor_burn, grasp_distance, sensitivity, AxonTravelTime, AbsoluteRefractoryPeriod, quiet_burn_rate, friction_time; BEGIN REAL PROCEDURE reproduction_demand; BEGIN reproduction_demand := 3 * frame_mass END reproduction_demand; REF (Genes) PROCEDURE mutated; BEGIN REAL PROCEDURE geometric_adjust (old_value, max_fractional_adjustment); REAL old_value, max_fractional_adjustment; BEGIN geometric_adjust := old_value * UNIFORM (1 - max_fractional_adjustment, 1 + max_fractional_adjustment, SEED) END geometric_adjust; REAL PROCEDURE bounded_adjust (old_value, min, max, drift); REAL old_value, min, max, drift; BEGIN REAL unnormalized_new_value; unnormalized_new_value := old_value + UNIFORM (- drift * (max-min), drift * (max-min), SEED); IF unnormalized_new_value < min THEN bounded_adjust := min ELSE IF unnormalized_new_value > max THEN bounded_adjust := max ELSE bounded_adjust := unnormalized_new_value END bounded_adjust; mutated :- NEW Genes (geometric_adjust(frame_mass, genetic_variability), geometric_adjust(motor_impulse, genetic_variability), bounded_adjust (sensor_angle, 0, PI/2, genetic_variability), bounded_adjust (motor_angle, 0, PI/2, genetic_variability), geometric_adjust(motor_burn, genetic_variability), geometric_adjust(grasp_distance, genetic_variability), geometric_adjust(sensitivity, genetic_variability), geometric_adjust(AxonTravelTime, genetic_variability), geometric_adjust(AbsoluteRefractoryPeriod, genetic_variability), geometric_adjust(quiet_burn_rate, genetic_variability), geometric_adjust(friction_time, genetic_variability) ) END mutated; END Genes; PROCESS CLASS food_pellet(id, mass, world, x, y); INTEGER id; REAL mass; REF (Environment) world; REAL x, y; BEGIN REAL PROCEDURE distance(other_x, other_y); REAL other_x, other_y; BEGIN distance := SQRT ((x-other_x)**2 + (y-other_y)**2) END distance; INTO (world.ListOfPellets); PASSIVATE END food_pellet; PROCESS CLASS dump_state (dump_tstep); REAL dump_tstep; BEGIN WHILE TRUE DO BEGIN REF (Vehicle2B) v; OUTTEXT ("Time="); OUTREAL (TIME,6,12); OUTIMAGE; OUTTEXT ("Vehicles:"); OUTIMAGE; v :- ListOfVehicles.FIRST; WHILE v =/= NONE DO BEGIN INSPECT v DO BEGIN REF (food_pellet) p; OUTTEXT ("Vehicle no. "); OUTINT(id,5); OUTIMAGE; OUTTEXT (" food_reserves x-position y-position"); OUTTEXT (" x-velocity y-velocity theta"); OUTIMAGE; OUTREAL(food_reserves,6,13); OUTREAL(x,6,13); OUTREAL(y,6,13); OUTREAL(vx,6,13); OUTREAL(vy,6,13); OUTREAL(theta(vx,vy),6,13); OUTIMAGE; OUTTEXT (" Food pellets:"); OUTIMAGE; OUTTEXT (" id mass x-position y-position"); OUTIMAGE; p :- world.ListOfPellets.FIRST; WHILE p =/= NONE DO BEGIN INSPECT p DO BEGIN OUTINT(id,5); OUTREAL(mass,6,13); OUTREAL(x,6,13); OUTREAL(y,6,13); OUTIMAGE END INSPECT; p :- p.SUC END WHILE; OUTIMAGE; END INSPECT; v :- v.SUC END WHILE; OUTIMAGE; OUTIMAGE; OUTIMAGE; IF ListOfVehicles.EMPTY THEN BEGIN OUTTEXT ("********** ALL VEHICLES DEAD **********"); OUTIMAGE; ACTIVATE MAIN END IF; HOLD (dump_tstep) END WHILE END dump_state; CLASS Environment; BEGIN REAL xmin, xmax, ymin, ymax; REF (HEAD) ListOfPellets; REF (MannaFromHeaven) m; xmin := world_xmin; xmax := world_xmax; ymin := world_ymin; ymax := world_ymax; ListOfPellets :- NEW HEAD; m :- NEW MannaFromHeaven (THIS Environment, min_pellet_mass, max_pellet_mass, pellet_arrival_rate); ACTIVATE m; END Environment; PROCESS CLASS MannaFromHeaven (world, min_mass, max_mass, rate); REF (Environment) world; REAL min_mass, max_mass, rate; COMMENT drops food pellets from heaven into the environment called "world" at random times given by the Poisson distribution at rate "rate", with masses uniformly distributed between "min_mass" and "max_mass", at random positions in the world, forever; BEGIN WHILE TRUE DO BEGIN HOLD (NEGEXP (rate, SEED)); ACTIVATE NEW food_pellet (unique_id(IDSTREAM_P), UNIFORM (min_mass, max_mass, SEED), world, UNIFORM (world.xmin, world.xmax, SEED), UNIFORM (world.ymin, world.ymax, SEED) ) END WHILE END MannaFromHeaven; REAL PROCEDURE theta (dx, dy); REAL dx, dy; COMMENT angle in [0, 2*pi) of vector dx, dy; BEGIN REAL unnormalized_theta; IF dx=0 THEN unnormalized_theta := PI/2 * SIGN(dy) ELSE unnormalized_theta := ARCTAN (dy/dx) + PI/2 * (1-SIGN(dx)); theta := MOD(unnormalized_theta, 2*PI) END theta; REAL PROCEDURE angular_separation (angle1, angle2); REAL angle1, angle2; COMMENT angle in [-pi, pi) going FROM angle1 TO angle2; BEGIN REAL unnormalized_angular_separation; unnormalized_angular_separation := MOD (angle2 - angle1, 2*PI); IF unnormalized_angular_separation >= PI THEN angular_separation := unnormalized_angular_separation - 2*PI ELSE angular_separation := unnormalized_angular_separation END angular_separation; REAL PROCEDURE MOD (a, b); REAL a, b; BEGIN MOD := a - b * ENTIER(a/b) END MOD; INTEGER PROCEDURE unique_id(U); NAME U; INTEGER U; BEGIN unique_id := U; U := U + 1 END unique_id; INTEGER SEED, IDSTREAM_V, IDSTREAM_P; REAL PI, degrees; REF (HEAD) ListOfVehicles; REAL world_xmin, world_xmax, world_ymin, world_ymax; REAL tstepmin,tstepmax; REAL genetic_variability; REAL min_pellet_mass, max_pellet_mass, pellet_arrival_rate; REAL dump_tstep; OUTTEXT("SIMULATION STARTING....."); OUTIMAGE; OUTIMAGE; OUTIMAGE; SEED := ININT; INIMAGE; OUTTEXT ("SEED="); OUTINT (SEED,10); OUTIMAGE; IDSTREAM_V := 1; IDSTREAM_P := 1; PI := 4*ARCTAN(1); degrees := PI/180; ListOfVehicles :- NEW HEAD; world_xmin := INREAL; INIMAGE; OUTTEXT ("world_xmin="); OUTREAL(world_xmin,6,13); OUTIMAGE; world_xmax := INREAL; INIMAGE; OUTTEXT ("world_xmax="); OUTREAL(world_xmax,6,13); OUTIMAGE; world_ymin := INREAL; INIMAGE; OUTTEXT ("world_ymin="); OUTREAL(world_ymin,6,13); OUTIMAGE; world_ymax := INREAL; INIMAGE; OUTTEXT ("world_ymax="); OUTREAL(world_ymax,6,13); OUTIMAGE; tstepmin := INREAL; INIMAGE; OUTTEXT ("tstepmin="); OUTREAL(tstepmin,6,13); OUTIMAGE; tstepmax := INREAL; INIMAGE; OUTTEXT ("tstepmax="); OUTREAL(tstepmax,6,13); OUTIMAGE; genetic_variability := INREAL; INIMAGE; OUTTEXT ("genetic_variability="); OUTREAL(genetic_variability,6,13); OUTIMAGE; min_pellet_mass := INREAL; INIMAGE; OUTTEXT ("min_pellet_mass="); OUTREAL(min_pellet_mass,6,13); OUTIMAGE; max_pellet_mass := INREAL; INIMAGE; OUTTEXT ("max_pellet_mass="); OUTREAL(max_pellet_mass,6,13); OUTIMAGE; pellet_arrival_rate := INREAL; INIMAGE; OUTTEXT ("pellet_arrival_rate="); OUTREAL(pellet_arrival_rate,6,13); OUTIMAGE; dump_tstep := INREAL; INIMAGE; OUTTEXT ("dump_tstep="); OUTREAL(dump_tstep,6,13); OUTIMAGE; OUTIMAGE; OUTIMAGE; OUTIMAGE; WHILE ~LASTITEM DO BEGIN REAL frame_mass, motor_impulse, sensor_angle, motor_angle, motor_burn, grasp_distance, sensitivity, AxonTravelTime, AbsoluteRefractoryPeriod, quiet_burn_rate, friction_time; frame_mass := INREAL; INIMAGE; motor_impulse := INREAL; INIMAGE; sensor_angle := INREAL; INIMAGE; motor_angle := INREAL; INIMAGE; motor_burn := INREAL; INIMAGE; grasp_distance := INREAL; INIMAGE; sensitivity := INREAL; INIMAGE; AxonTravelTime := INREAL; INIMAGE; AbsoluteRefractoryPeriod := INREAL; INIMAGE; quiet_burn_rate := INREAL; INIMAGE; friction_time := INREAL; INIMAGE; ACTIVATE NEW Vehicle2B (unique_id(IDSTREAM_V), NEW Genes (frame_mass, motor_impulse, sensor_angle, motor_angle, motor_burn, grasp_distance, sensitivity, AxonTravelTime, AbsoluteRefractoryPeriod, quiet_burn_rate, friction_time), NEW Environment, UNIFORM(world_xmin, world_xmax, SEED), UNIFORM(world_ymin, world_ymax, SEED), 0, 0) .with_food_reserves (frame_mass * 0.5); END WHILE; ACTIVATE NEW dump_state (dump_tstep); PASSIVATE; OUTTEXT("END OF SIMULATION RUN, TIME="); OUTREAL(TIME,6,13); OUTIMAGE; END