Программирование ИИ в приложениях(тексты примеров)

Download Программирование ИИ в приложениях(тексты примеров)

If you can't read please download the document

Post on 08-Dec-2016

263 views

Category:

Documents


20 download

TRANSCRIPT

- ( )/ai.rar

software/ch02/emsa/common.h

/* * Simulated Annealing Symbolics and Function Prototypes * * ./software/ch2/emsa/common.h * * [email protected] * */

#include

#define MAX_LENGTH30

typedef int solutionType[MAX_LENGTH];

typedef struct { solutionType solution; float energy;} memberType;

/* Annealing Schedule */#define INITIAL_TEMPERATURE30.0#define FINAL_TEMPERATURE0.5#define ALPHA0.99#define STEPS_PER_CHANGE100

/* Return a random number between 0 and 1 */#define getSRand()((float)rand() / (float)RAND_MAX)

/* Return an integer from 0..(x-1) */#define getRand(x)(int)((x) * getSRand())

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch02/emsa/emsa.c

/* * Simulated Annealing Implementation for the n-Queens Problem * * ./software/ch2/emsa/emsa.c * * [email protected] * */

#include #include #include #include #include "common.h"

/* * tweakSolution() * * Randomly perturb an encoded solution. * */

void tweakSolution( memberType *member ){ int temp, x, y;

x = getRand(MAX_LENGTH); do { y = getRand(MAX_LENGTH); } while (x == y);

temp = member->solution[x]; member->solution[x] = member->solution[y]; member->solution[y] = temp;}

/* * initializeSolution() * * Randomly initialize an encoded-solution. * */

void initializeSolution( memberType *member ){ int i;

/* Initial setup of the solution */ for (i = 0 ; i < MAX_LENGTH ; i++) { member->solution[i] = i; }

/* Randomly perturb the solution */ for (i = 0 ; i < MAX_LENGTH ; i++) { tweakSolution( member ); }

}

/* * emitSolution() * * Emit the passed solution as an N by N board. * */

void emitSolution( memberType *member ){ char board[MAX_LENGTH][MAX_LENGTH]; int x, y;

bzero( (void *)board, MAX_LENGTH * MAX_LENGTH );

for (x = 0 ; x < MAX_LENGTH ; x++) { board[x][member->solution[x]] = 'Q'; }

printf("board:\n"); for (y = 0 ; y < MAX_LENGTH ; y++) { for (x = 0 ; x < MAX_LENGTH ; x++) { if (board[x][y] == 'Q') printf("Q "); else printf(". "); } printf("\n"); } printf("\n\n");}

/* * computeEnergy() * * Calculate the energy of the passed solution. The energy is the * the number of conflicts on the board. Note that only diagonals * are checked. The encoding ensures that no veritical or horizontal * conflicts are possible. * */

void computeEnergy( memberType *member ){ int i, j, x, y, tempx, tempy; char board[MAX_LENGTH][MAX_LENGTH]; int conflicts; const int dx[4] = {-1, 1, -1, 1}; const int dy[4] = {-1, 1, 1, -1};

bzero( (void *)board, MAX_LENGTH * MAX_LENGTH );

for (i = 0 ; i < MAX_LENGTH ; i++) { board[i][member->solution[i]] = 'Q'; }

/* Walk through each of the Queens, and compute the number of conflicts */ conflicts = 0;

for (i = 0 ; i < MAX_LENGTH ; i++) {

x = i; y = member->solution[i];

/* NOTE: Based upon the encoding, horizontal and vertical conflicts will * never occur!!! */

/* Check diagonals */ for (j = 0 ; j < 4 ; j++) {

tempx = x ; tempy = y; while(1) { tempx += dx[j]; tempy += dy[j]; if ((tempx < 0) || (tempx >= MAX_LENGTH) || (tempy < 0) || (tempy >= MAX_LENGTH)) break; if (board[tempx][tempy] == 'Q') conflicts++; }

}

}

member->energy = (float)conflicts;}

/* * copySolution * * Copy the src member structure to the dest member structure. * */

void copySolution( memberType *dest, memberType *src ){ int i;

for (i = 0 ; i < MAX_LENGTH ; i++) { dest->solution[i] = src->solution[i]; } dest->energy = src->energy;}

/* * main() * * Main function for the simulated annealing demonstration. * */

int main(){ int timer=0, step, solution=0, useNew, accepted; float temperature = INITIAL_TEMPERATURE; memberType current, working, best; FILE *fp;

fp = fopen("stats.txt", "w");

srand(time(NULL));

initializeSolution( &current ); computeEnergy( &current ); best.energy = 100.0;

copySolution( &working, &current);

while (temperature > FINAL_TEMPERATURE) {

printf("Temperature : %f\n", temperature);

accepted = 0;

/* Monte Carlo Step */ for (step = 0 ; step < STEPS_PER_CHANGE ; step++) {

useNew = 0;

tweakSolution( &working ); computeEnergy( &working );

if (working.energy test) {

accepted++; useNew = 1;

}

}

if (useNew) { useNew = 0; copySolution( &current, &working );

if (current.energy < best.energy) { copySolution( &best, &current ); solution = 1; }

} else {

copySolution( &working, &current);

}

}

fprintf(fp, "%d %f %f %d\n", timer++, temperature, best.energy, accepted);

printf("Best energy = %f\n", best.energy);

temperature *= ALPHA; }

fclose(fp);

if (solution) { emitSolution( &best ); }

return 0;}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch02/emsa/Makefile

## Makefile for emhttp#

CC = gcc

OBJS =emsa.o

all:emsa

emsa: $(OBJS)$(CC) -g -o emsa $(OBJS) -lm

.c.o:$(CC) $(CFLAGS) -g -Wall -c $solution[x]; member->solution[x] = member->solution[y]; member->solution[y] = temp;}

/* * emitSolution() * * Emit a solution in chessboard form. * */

void emitSolution( memberType *member ){ char board[MAX_LENGTH][MAX_LENGTH]; int x, y;

bzero( (void *)board, MAX_LENGTH * MAX_LENGTH );

for (x = 0 ; x < MAX_LENGTH ; x++) { board[x][member->solution[x]-1] = 'Q'; }

printf("board:\n"); for (y = 0 ; y < MAX_LENGTH ; y++) { for (x = 0 ; x < MAX_LENGTH ; x++) { if (board[x][y] == 'Q') printf("Q "); else printf(". "); } printf("\n"); } printf("\n\n");}

/* * computeEnergy() * * Calculate the energy of the passed solution. The energy is the * the number of conflicts on the board. Note that only diagonals * are checked. The encoding ensures that no veritical or horizontal * conflicts are possible. * */

float computeEnergy( memberType *member ){ int i, j, x, y, tempx, tempy; char board[MAX_LENGTH][MAX_LENGTH]; int conflicts; const int dx[4] = {-1, 1, -1, 1}; const int dy[4] = {-1, 1, 1, -1};

bzero( (void *)board, MAX_LENGTH * MAX_LENGTH );

for (i = 0 ; i < MAX_LENGTH ; i++) { board[i][member->solution[i]-1] = 'Q'; }

/* Walk through each of the Queens, and compute the number of conflicts */ conflicts = 0;

for (i = 0 ; i < MAX_LENGTH ; i++) {

x = i; y = member->solution[i]-1;

/* NOTE: Based upon encoding, horizontal and vertical conflicts will * never occur!!! */

/* Check diagonals */ for (j = 0 ; j < 4 ; j++) {

tempx = x ; tempy = y; while(1) { tempx += dx[j]; tempy += dy[j]; if ((tempx < 0) || (tempx >= MAX_LENGTH) || (tempy < 0) || (tempy >= MAX_LENGTH)) break; if (board[tempx][tempy] == 'Q') conflicts++; }

}

}

return (float)conflicts;}

/* * simulatedAnnealing() * * Perform the simulated annealing algorithm. * */

int simulateAnnealing( float curTemp ){ int member, i; memberType tempMember; float energy; int useNew = 0; int solution = -1;

for (member = 0 ; member < MAX_MEMBERS ; member++) {

for (i = 0 ; i < MAX_LENGTH ; i++) { tempMember.solution[i] = population[member].solution[i]; }

tweakSolution( &tempMember );

energy = computeEnergy( &tempMember );

useNew = 0;

if (energy < population[member].energy) { useNew = 1; } else { float test = getSRand(); float delta = energy - population[member].energy;

if (exp(-delta/curTemp) > test) { useNew = 1; } }

if (useNew) {

for (i = 0 ; i < MAX_LENGTH ; i++) { population[member].solution[i] = tempMember.solution[i]; population[member].energy = energy; }

}

if (population[member].energy == 0) solution = member;

}

return solution;}

/* * computeAllEnergy() * * Run through the population and compute the energy for each * candidate solution. * */

void computeAllEnergy( void ){ int member;

for (member = 0 ; member < MAX_MEMBERS ; member++) { population[member].energy = computeEnergy( &population[member] ); }

}

/* * main() * * Main function for the simulated annealing demonstration. * */

int main(){ int step, solution = -1; float temperature = INITIAL_TEMPERATURE;

srand(time(NULL));

initializePopulation();

computeAllEnergy();

while (temperature > FINAL_TEMPERATURE) {

printf("temperature %f (solution %d)\n", temperature, solution);

for (step = 0 ; step < STEPS_PER_CHANGE ; step++) { solution = simulateAnnealing( temperature ); }

temperature -= RATE; }

if (solution == -1) { printf("No solution found\n"); } else { emitSolution( &population[solution] ); }

return 0;}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch02/emsapop/Makefile

## Makefile for emhttp#

CC = gcc

OBJS =emsapop.o

all:emsapop

emsapop: $(OBJS)$(CC) -o emsapop $(OBJS) -lm

.c.o:$(CC) $(CFLAGS) -Wall -c $ test) {

/* Test for vigilance acceptability */

#ifdef DEBUG printf("step 4 : testing vigilance %f < %f\n", ((float)magPE/(float)magE), vigilance);#endif

if (((float)magPE/(float)magE) < vigilance) {

int old;

/* Ensure this is a different cluster */ if (membership[index] != pvec) {

old = membership[index]; membership[index] = pvec;

#ifdef DEBUG printf("Moved example %d from cluster %d to %d\n", index, old, pvec);#endif

if (old >= 0) { members[old]--; if (members[old] == 0) numPrototypeVectors--; } members[pvec]++;

/* Recalculate the prototype vectors for the old and new * clusters. */ if ((old >= 0) && (old < TOTAL_PROTOTYPE_VECTORS)) { updatePrototypeVectors( old ); }

updatePrototypeVectors( pvec );

done = 0; break;

} else { /* Already in this cluster */ }

} /* vigilance test */

}

}

} /* for vector loop */

/* Check to see if the current vector was processed */ if (membership[index] == -1) { /* No prototype vector was found to be close to the example * vector. Create a new prototype vector for this example. */ membership[index] = createNewPrototypeVector( &database[index][0] ); done = 0; }

} /* customers loop */

#ifdef DEBUG printf("\n");#endif

if (!count--) break;

} /* !done */

return 0;}

/* * makeRecommendation( int customer ) * * Given a customer feature vector and the prototype vector, choose the * item within the vector that the customer feature vector does not have * (is 0) and has the highest sumVector for the cluster. * */

void makeRecommendation ( int customer ){ int bestItem = -1; int val = 0; int item;

for (item = 0 ; item < MAX_ITEMS ; item++) {

if ((database[customer][item] == 0) && (sumVector[membership[customer]][item] > val)) { bestItem = item; val = sumVector[membership[customer]][item]; }

}

printf("For Customer %d, ", customer);

if (bestItem >= 0) { printf("The best recommendation is %d (%s)\n", bestItem, itemName[bestItem]); printf("Owned by %d out of %d members of this cluster\n", sumVector[membership[customer]][bestItem], members[membership[customer]]); } else { printf("No recommendation can be made.\n"); }

printf("Already owns: "); for (item = 0 ; item < MAX_ITEMS ; item++) { if (database[customer][item]) printf("%s ", itemName[item]); } printf("\n\n");}

/* * main() * * Initialize, perform the ART1 algorithm, display the customer data and * then make a recommendation. * */int main(){ int customer;

srand( time( NULL ) );

initialize();

performART1();

displayCustomerDatabase();

for (customer = 0 ; customer < MAX_CUSTOMERS ; customer++) { makeRecommendation( customer ); }

return 0;}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch04/antalg.c

/* * Ant Algorithm Demonstration * * ./software/ch4/antalg.c * * [email protected] * */

#include #include #include #include "common.h"

cityType cities[MAX_CITIES];

antType ants[MAX_ANTS];

/* From To */double distance[MAX_CITIES][MAX_CITIES];

/* From To */double pheromone[MAX_CITIES][MAX_CITIES];

double best=(double)MAX_TOUR;int bestIndex;

/* * init() * * Initialize the cities, their distances and the Ant population. * */

void init( void ){ int from, to, ant;

/* Create the cities and their locations */ for (from = 0 ; from < MAX_CITIES ; from++) {

/* Randomly place cities around the grid */ cities[from].x = getRand( MAX_DISTANCE ); cities[from].y = getRand( MAX_DISTANCE );

for (to = 0 ; to < MAX_CITIES ; to++) { distance[from][to] = 0.0; pheromone[from][to] = INIT_PHEROMONE; }

}

/* Compute the distances for each of the cities on the map */ for ( from = 0 ; from < MAX_CITIES ; from++) {

for ( to = 0 ; to < MAX_CITIES ; to++) {

if ((to != from) && (distance[from][to] == 0.0)) { int xd = abs(cities[from].x - cities[to].x); int yd = abs(cities[from].y - cities[to].y);

distance[from][to] = sqrt( (xd * xd) + (yd * yd) ); distance[to][from] = distance[from][to]; }

}

}

/* Initialize the ants */ to = 0; for ( ant = 0 ; ant < MAX_ANTS ; ant++ ) {

/* Distribute the ants to each of the cities uniformly */ if (to == MAX_CITIES) to = 0; ants[ant].curCity = to++;

for ( from = 0 ; from < MAX_CITIES ; from++ ) { ants[ant].tabu[from] = 0; ants[ant].path[from] = -1; }

ants[ant].pathIndex = 1; ants[ant].path[0] = ants[ant].curCity; ants[ant].nextCity = -1; ants[ant].tourLength = 0.0;

/* Load the ant's current city into taboo */ ants[ant].tabu[ants[ant].curCity] = 1;

}}

/* * restartAnts() * * Reinitialize the ant population to start another tour around the * graph. * */

void restartAnts( void ){ int ant, i, to=0;

for ( ant = 0 ; ant < MAX_ANTS ; ant++ ) {

if (ants[ant].tourLength < best) { best = ants[ant].tourLength; bestIndex = ant; }

ants[ant].nextCity = -1; ants[ant].tourLength = 0.0;

for (i = 0 ; i < MAX_CITIES ; i++) { ants[ant].tabu[i] = 0; ants[ant].path[i] = -1; }

if (to == MAX_CITIES) to = 0; ants[ant].curCity = to++;

ants[ant].pathIndex = 1; ants[ant].path[0] = ants[ant].curCity;

ants[ant].tabu[ants[ant].curCity] = 1;

}

}

/* * antProduct() * * Compute the denominator for the path probability equation (concentration * of pheromone of the current path over the sum of all concentrations of * available paths). * */

double antProduct( int from, int to ){ return (( pow( pheromone[from][to], ALPHA ) * pow( (1.0 / distance[from][to]), BETA ) ));}

/* * selectNextCity() * * Using the path probability selection algorithm and the current pheromone * levels of the graph, select the next city the ant will travel to. * */

int selectNextCity( int ant ){ int from, to; double denom=0.0;

/* Choose the next city to visit */ from = ants[ant].curCity;

/* Compute denom */ for (to = 0 ; to < MAX_CITIES ; to++) { if (ants[ant].tabu[to] == 0) { denom += antProduct( from, to ); } }

assert(denom != 0.0);

do {

double p;

to++; if (to >= MAX_CITIES) to = 0;

if ( ants[ant].tabu[to] == 0 ) {

p = antProduct(from, to)/denom;

if (getSRand() < p ) break;

}

} while (1);

return to;}

/* * simulateAnts() * * Simulate a single step for each ant in the population. This function * will return zero once all ants have completed their tours. * */

int simulateAnts( void ){ int k; int moving = 0;

for (k = 0 ; k < MAX_ANTS ; k++) {

/* Ensure this ant still has cities to visit */ if (ants[k].pathIndex < MAX_CITIES) {

ants[k].nextCity = selectNextCity( k );

ants[k].tabu[ants[k].nextCity] = 1;

ants[k].path[ants[k].pathIndex++] = ants[k].nextCity;

ants[k].tourLength += distance[ants[k].curCity][ants[k].nextCity];

/* Handle the final case (last city to first) */ if (ants[k].pathIndex == MAX_CITIES) { ants[k].tourLength += distance[ants[k].path[MAX_CITIES-1]][ants[k].path[0]]; }

ants[k].curCity = ants[k].nextCity;

moving++;

}

}

return moving;}

/* * updateTrails() * * Update the pheromone levels on each arc based upon the number of ants * that have travelled over it, including evaporation of existing pheromone. * */

void updateTrails( void ){ int from, to, i, ant;

/* Pheromone Evaporation */ for (from = 0 ; from < MAX_CITIES ; from++) {

for (to = 0 ; to < MAX_CITIES ; to++) {

if (from != to) {

pheromone[from][to] *= (1.0 - RHO);

if (pheromone[from][to] < 0.0) pheromone[from][to] = INIT_PHEROMONE;

}

}

}

/* Add new pheromone to the trails */

/* Look at the tours of each ant */ for (ant = 0 ; ant < MAX_ANTS ; ant++) {

/* Update each leg of the tour given the tour length */ for (i = 0 ; i < MAX_CITIES ; i++) {

if (i < MAX_CITIES-1) { from = ants[ant].path[i]; to = ants[ant].path[i+1]; } else { from = ants[ant].path[i]; to = ants[ant].path[0]; }

pheromone[from][to] += (QVAL / ants[ant].tourLength); pheromone[to][from] = pheromone[from][to];

}

}

for (from = 0 ; from < MAX_CITIES ; from++) { for (to = 0 ; to < MAX_CITIES ; to++) { pheromone[from][to] *= RHO; } }

}

/* * emitDataFile() * * For the ant with the best tour (shortest tour through the graph), emit * the path in two data files (plotted together). * */

void emitDataFile( int ant ){ int city; FILE *fp;

fp = fopen("cities.dat", "w"); for (city = 0 ; city < MAX_CITIES ; city++) { fprintf(fp, "%d %d\n", cities[city].x, cities[city].y); } fclose(fp);

fp = fopen("solution.dat", "w"); for (city = 0 ; city < MAX_CITIES ; city++) { fprintf(fp, "%d %d\n", cities[ ants[ant].path[city] ].x, cities[ ants[ant].path[city] ].y ); } fprintf(fp, "%d %d\n", cities[ ants[ant].path[0] ].x, cities[ ants[ant].path[0] ].y );

fclose(fp);}

void emitTable( void ){ int from, to;

for (from = 0 ; from < MAX_CITIES ; from++) { for (to = 0 ; to < MAX_CITIES ; to++) { printf("%5.2g ", pheromone[from][to]); } printf("\n"); } printf("\n");}

/* * main() * * Main function for the ant algorithm. Performs the simulation given the * constraints defined in common.h. * */

int main(){ int curTime = 0;

srand( time(NULL) );

init();

while (curTime++ < MAX_TIME) {

if ( simulateAnts() == 0 ) {

updateTrails();

if (curTime != MAX_TIME) restartAnts();

printf("Time is %d (%g)\n", curTime, best);

}

}

printf("best tour %g\n", best); printf("\n\n");

emitDataFile( bestIndex );

return 0;}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch04/common.h

/* * Ant Algorotihms Symbolics, Types and Function Prototypes. * * ./software/ch4/common.h * * [email protected] * */

#ifndef __COMMON_H#define __COMMON_H

#include #include

#define MAX_CITIES15

#define MAX_DISTANCE100

#define MAX_TOUR(MAX_CITIES * MAX_DISTANCE)

typedef struct {int x;int y;} cityType;

#define MAX_ANTS20

typedef struct {int curCity;int nextCity;unsigned char tabu[MAX_CITIES];int pathIndex;unsigned char path[MAX_CITIES];double tourLength;} antType;

#define getSRand()((float)rand() / (float)RAND_MAX)#define getRand(x)(int)((x) * getSRand())

#define ALPHA1.0#define BETA5.0#define RHO0.5/* Intensity / Evaporation */#define QVAL100

#define MAX_TOURS500

#define MAX_TIME(MAX_TOURS * MAX_CITIES)

#define INIT_PHEROMONE(1.0 / MAX_CITIES)

#endif /* __COMMON_H */

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch04/Makefile

## Makefile for emhttp#

CC = gccCFLAGS = -g

OBJS =antalg.o

all:antalg

antalg: $(OBJS)$(CC) -o antalg $(OBJS) -lm

antalg: antalg.c

.c.o:$(CC) $(CFLAGS) -Wall -c $ max) { max = vector[index]; sel = index; } }

return( sel );}

/* * main() * * Main function for the backpropagation network. * */

int main(){ double err; int i, sample=0, iterations=0; int sum = 0;

out = fopen("stats.txt", "w");

/* Seed the random number generator */ srand( time(NULL) );

assignRandomWeights();

while (1) {

if (++sample == MAX_SAMPLES) sample = 0; inputs[0] = samples[sample].health; inputs[1] = samples[sample].knife; inputs[2] = samples[sample].gun; inputs[3] = samples[sample].enemy;

target[0] = samples[sample].out[0]; target[1] = samples[sample].out[1]; target[2] = samples[sample].out[2]; target[3] = samples[sample].out[3];

feedForward();

/* need to iterate through all ... */ err = 0.0; for (i = 0 ; i < OUTPUT_NEURONS ; i++) { err += sqr( (samples[sample].out[i] - actual[i]) ); } err = 0.5 * err;

fprintf(out, "%g\n", err); printf("mse = %g\n", err);

if (iterations++ > 100000) break;

backPropagate();

}

/* Test the network */ for (i = 0 ; i < MAX_SAMPLES ; i++) {

inputs[0] = samples[i].health; inputs[1] = samples[i].knife; inputs[2] = samples[i].gun; inputs[3] = samples[i].enemy;

target[0] = samples[i].out[0]; target[1] = samples[i].out[1]; target[2] = samples[i].out[2]; target[3] = samples[i].out[3];

feedForward();

if (action(actual) != action(target)) {

printf("%2.1g:%2.1g:%2.1g:%2.1g %s (%s)\n", inputs[0], inputs[1], inputs[2], inputs[3], strings[action(actual)], strings[action(target)]);

} else { sum++; }

}

printf("Network is %g%% correct\n", ((float)sum / (float)MAX_SAMPLES) * 100.0);

/* Run some tests */

/* Health Knife Gun Enemy */ inputs[0] = 2.0; inputs[1] = 1.0; inputs[2] = 1.0; inputs[3] = 1.0; feedForward(); printf("2111 Action %s\n", strings[action(actual)]);

inputs[0] = 1.0; inputs[1] = 1.0; inputs[2] = 1.0; inputs[3] = 2.0; feedForward(); printf("1112 Action %s\n", strings[action(actual)]);

inputs[0] = 0.0; inputs[1] = 0.0; inputs[2] = 0.0; inputs[3] = 0.0; feedForward(); printf("0000 Action %s\n", strings[action(actual)]);

inputs[0] = 0.0; inputs[1] = 1.0; inputs[2] = 1.0; inputs[3] = 1.0; feedForward(); printf("0111 Action %s\n", strings[action(actual)]);

inputs[0] = 2.0; inputs[1] = 0.0; inputs[2] = 1.0; inputs[3] = 3.0; feedForward(); printf("2013 Action %s\n", strings[action(actual)]);

inputs[0] = 2.0; inputs[1] = 1.0; inputs[2] = 0.0; inputs[3] = 3.0; feedForward(); printf("2103 Action %s\n", strings[action(actual)]);

inputs[0] = 0.0; inputs[1] = 1.0; inputs[2] = 0.0; inputs[3] = 3.0; feedForward(); printf("0103 Action %s\n", strings[action(actual)]);

fclose(out);

return 0;}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch05/Makefile

## Makefile for emhttp#

CC = gccCFLAGS =

OBJS =backprop.o

all:backprop

backprop: $(OBJS)$(CC) -o backprop $(OBJS) -lm

backprop: backprop.c

.c.o:$(CC) $(CFLAGS) -Wall -c $ maxFitness) { maxFitness = populations[curPop][chrom].fitness; } else if (populations[curPop][chrom].fitness < minFitness) { minFitness = populations[curPop][chrom].fitness; }

totFitness += populations[curPop][chrom].fitness;

}

avgFitness = totFitness / (float)MAX_CHROMS;

if (outP) { fprintf(outP, "%d %6.4f %6.4f %6.4f\n", x++, minFitness, avgFitness, maxFitness); }

return 0;}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch06/init.c

/* * Genetic Algorithm Population Initialization * * ./software/ch6/init.c * * [email protected] * */

#include #include #include #include "common.h"

POPULATION_TYPE populations[2][MAX_CHROMS];

int curPop;

/* * initMember() * * Initialize a single member in the population. This includes the * initial fitness, program size and the initial set of random * instructions. * */

void initMember( pop, index ){ int progIndex;

populations[pop][index].fitness = 0.0; populations[pop][index].progSize = MAX_PROGRAM-1;

progIndex = 0; while (progIndex < MAX_PROGRAM) { populations[pop][index].program[progIndex++] = getRand(MAX_INSTRUCTION); }

}

/* * initPopulation() * * Initialize all of the chromosomes in the population (potential * solutions to the given problem). * */

void initPopulation( void ){ int index;

for (index = 0 ; index < MAX_CHROMS ; index++) { initMember(curPop, index); }}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch06/main.c

/* * Genetic Algorithm main() * * ./software/ch6/main.c * * [email protected] * */

#include #include #include #include "common.h"

extern void initPopulation(void);extern POPULATION_TYPE populations[2][MAX_CHROMS];

/* * main() * * This is the main function for the genetic algorithm simulation. * */

int main(){ int generation = 0, i; FILE *fp; extern float minFitness, maxFitness, avgFitness; extern int curCrossovers, curMutations; extern int curPop;

void printProgram( int, int );

srand(time(NULL));

curPop = 0;

fp = fopen("stats.txt", "w");

if (fp == NULL) exit(-1);

initPopulation(); performFitnessCheck( fp );

while (generation < MAX_GENERATIONS) {

curCrossovers = curMutations = 0;

performSelection();

/* Switch the populations */ curPop = (curPop == 0) ? 1 : 0;

performFitnessCheck( fp );

if ((generation++ % 100) == 0) { printf("Generation %d\n", generation-1); printf("\tmaxFitness = %f (%g)\n", maxFitness, MAX_FIT); printf("\tavgFitness = %f\n", avgFitness); printf("\tminFitness = %f\n", minFitness); printf("\tCrossovers = %d\n", curCrossovers); printf("\tMutation = %d\n", curMutations); printf("\tpercentage = %f\n", avgFitness / maxFitness); }

if ( generation > (MAX_GENERATIONS * 0.25) ) { if ((avgFitness / maxFitness) > 0.98) { printf("converged\n"); break; } }

if (maxFitness == MAX_FIT) { printf("found solution\n"); break; }

}

printf("Generation %d\n", generation-1); printf("\tmaxFitness = %f (%g)\n", maxFitness, MAX_FIT); printf("\tavgFitness = %f\n", avgFitness); printf("\tminFitness = %f\n", minFitness); printf("\tCrossovers = %d\n", curCrossovers); printf("\tMutation = %d\n", curMutations); printf("\tpercentage = %f\n", avgFitness / maxFitness);

for (i = 0 ; i < MAX_CHROMS ; i++) {

if (populations[curPop][i].fitness == maxFitness) { int index; printf("Program %3d : ", i);

for (index = 0 ; index < populations[curPop][i].progSize ; index++) { printf("%02d ", populations[curPop][i].program[index]); } printf("\n"); printf("Fitness %f\n", populations[curPop][i].fitness); printf("ProgSize %d\n\n", populations[curPop][i].progSize);

printProgram(i, curPop);

break; }

}

return 0;}

/* * printProgram * * This function emits the program for a given chromosome in the defined * population. It is test code only and is not used in the simulation. * */

char *tins[]={ "DUP", "SWAP", "MUL", "ADD", "OVER", "NOP" };

void printProgram( int index, int curPop ){ int i;

for (i = 0 ; i < populations[curPop][index].progSize ; i++) { printf("%s\n", tins[ populations[curPop][index].program[i] ] ); }}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch06/Makefile

## Makefile for emhttp#

CC = gccCFLAGS =

OBJS =stm.o select.o fitness.o init.o main.o

all:stm

stm: $(OBJS)$(CC) -o stm $(OBJS)

.c.o:$(CC) $(CFLAGS) -Wall -c $ b) ? a : b)

extern POPULATION_TYPE populations[2][MAX_CHROMS];extern int curPop;

extern float maxFitness;extern float avgFitness;extern float minFitness;

int curMutations, curCrossovers;

/* * selectParent() * * This function selects a parent from the current generation using * a form of the roulette-wheel selection method. * */

int selectParent( void ){ static int chrom = 0; int ret = -1; float retFitness = 0.0;

do {

retFitness = (populations[curPop][chrom].fitness / maxFitness);

if (chrom == MAX_CHROMS) chrom = 0;

if (populations[curPop][chrom].fitness > minFitness) { if (getSRand() < retFitness) { ret = chrom++; retFitness = populations[curPop][chrom].fitness; break; } }

chrom++;

} while (1);

return ret;}

/* * performReproduction() * * This function performs the actual reproduction. Given two parents * and two children, the parents are recombined into the two children * in the next generation. If crossover is to be performed, a * crossover point is selected (the point at which the parent's * chromosomes tail's will be split to the two children). The mutation * operator may also be performed, on each gene as it's copied from * the parent to the child. * */

int performReproduction( int parentA, int parentB, int childA, int childB ){ int crossPoint, i; int nextPop = (curPop == 0) ? 1 : 0;

int mutate( int );

if (getSRand() > XPROB) { crossPoint = getRand(MAX(populations[curPop][parentA].progSize-2, populations[curPop][parentB].progSize-2))+1; curCrossovers++; } else { crossPoint = MAX_PROGRAM; }

for (i = 0 ; i < crossPoint ; i++) { populations[nextPop][childA].program[i] = mutate(populations[curPop][parentA].program[i]); populations[nextPop][childB].program[i] = mutate(populations[curPop][parentB].program[i]); }

for ( ; i < MAX_PROGRAM ; i++) { populations[nextPop][childA].program[i] = mutate(populations[curPop][parentB].program[i]); populations[nextPop][childB].program[i] = mutate(populations[curPop][parentA].program[i]); }

populations[nextPop][childA].progSize = populations[curPop][parentA].progSize; populations[nextPop][childB].progSize = populations[curPop][parentB].progSize;

return 0;}

/* * mutate() * * This function returns a random instruction mimicing the process * of mutation. The current gene of the chromosome is passed in, * which could be used to create the new chromosome (as a random * bit replacement). This function currently does not use it. * */

int mutate(int gene) { float temp = getSRand(); if (temp > MPROB) { gene = getRand(MAX_INSTRUCTION); curMutations++; } return gene;}

/* * performSelection() * * This function selects two parents from the current population and * recombines them into two children for the next generation. The * process of recombination includes both crossover and mutation * (dependent upon the probabilities for each). * */

int performSelection( void ){ int par1, par2; int child1, child2; int chrom;

for (chrom = 0 ; chrom < MAX_CHROMS ; chrom+=2) {

par1 = selectParent(); par2 = selectParent();

child1 = chrom; child2 = chrom+1;

performReproduction( par1, par2, child1, child2 );

} return 0;}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch06/stm.c

/* * Genetic Algorithm Stack Machine (Virtual Computer) Implementation * * ./software/ch6/stm.c * * [email protected] * */

#include #include "common.h"

#define STACK_DEPTH25

int stack[STACK_DEPTH];int stackPointer;

#define ASSERT_STACK_ELEMENTS(x) \ if (stackPointer < x) { error = STACK_VIOLATION ; break; }

#define ASSERT_STACK_NOT_FULL \ if (stackPointer == STACK_DEPTH) { error = STACK_VIOLATION ; break; }

#define SPUSH(x) (stack[stackPointer++] = x)#define SPOP (stack[--stackPointer])#define SPEEK (stack[stackPointer-1])

/* * interpretSTM() * * This function is the stack machine interpreter. The program, its * length, and 'argsLength' number of arguments are passed to perform * whatever function is provided within 'program'. Upon completion, * any error encountered is returned to the caller. The global stack * 'stack' is used to determine the result of the program and to test * what was expected (which determines the fitness). * */

int interpretSTM(const int *program, int progLength, const int *args, int argsLength){ int pc = 0; int i, error = NONE; int a, b;

stackPointer = 0;

/* Load the arguments onto the stack */ for (i = argsLength-1 ; i >= 0 ; i--) { SPUSH(args[i]); } /* Execute the program */ while ((error == NONE) && (pc < progLength)) {

switch(program[pc++]) {

case DUP: ASSERT_STACK_ELEMENTS(1); ASSERT_STACK_NOT_FULL; SPUSH(SPEEK); break;

case SWAP: ASSERT_STACK_ELEMENTS(2); a = stack[stackPointer-1]; stack[stackPointer-1] = stack[stackPointer-2]; stack[stackPointer-2] = a; break;

case MUL: ASSERT_STACK_ELEMENTS(2); a = SPOP; b = SPOP; SPUSH(a * b); break;

case ADD: ASSERT_STACK_ELEMENTS(2); a = SPOP; b = SPOP; SPUSH(a + b); break;

case OVER: ASSERT_STACK_ELEMENTS(2); SPUSH(stack[stackPointer-2]); break;

} /* Switch opcode */

} /* Loop */

return(error);}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch07/common.h

/* * Artificial Life Simulation Types and Symbolic Constants * * ./software/ch7/common.h * * [email protected] * */

#ifndef __COMMON_H#define __COMMON_H

#include #include

/* Sensor Input Cells */

#define HERB_FRONT0#define CARN_FRONT1#define PLANT_FRONT2#define HERB_LEFT3#define CARN_LEFT4#define PLANT_LEFT5#define HERB_RIGHT6#define CARN_RIGHT7#define PLANT_RIGHT8#define HERB_PROXIMITY9#define CARN_PROXIMITY10#define PLANT_PROXIMITY11

#define MAX_INPUTS12

/* Output Cells */ #define ACTION_TURN_LEFT0#define ACTION_TURN_RIGHT1#define ACTION_MOVE2#define ACTION_EAT3

#define MAX_OUTPUTS4

/* Total number of weights (and biases) for an agent */

#define TOTAL_WEIGHTS((MAX_INPUTS * MAX_OUTPUTS) + MAX_OUTPUTS)

/* Description of the 3 planes for the 2d grid */

#define HERB_PLANE0#define CARN_PLANE1#define PLANT_PLANE2

/* Available directions */

#define NORTH0#define SOUTH1#define EAST2#define WEST3

#define MAX_DIRECTION4

/* Types for location, plants and agents */

typedef struct { short x; short y;} locType;

typedef struct { locType location;} plantType;

typedef struct { short type; short energy; short parent; short age; short generation; locType location; unsigned short direction; short inputs[MAX_INPUTS]; short weight_oi[MAX_INPUTS * MAX_OUTPUTS]; short biaso[MAX_OUTPUTS]; short actions[MAX_OUTPUTS];} agentType;

#define TYPE_HERBIVORE0#define TYPE_CARNIVORE1#define TYPE_DEAD-1

typedef struct { short y_offset; short x_offset;} offsetPairType;

/* Grid offsets for Front/Left/Right/Proximity (North/-South facing) */

const offsetPairType northFront[]= {{-2,-2}, {-2,-1}, {-2,0}, {-2,1}, {-2,2}, {9,9}};const offsetPairType northLeft[]={{0,-2}, {-1,-2}, {9,9}};const offsetPairType northRight[]={{0,2}, {-1,2}, {9,9}};const offsetPairType northProx[]= {{0,-1}, {-1,-1}, {-1,0}, {-1,1}, {0,1}, {9,9}};

/* Grid offsets for Front/Left/Right/Proximity (West/-East facing) */

const offsetPairType westFront[]= {{2,-2}, {1,-2}, {0,-2}, {-1,-2}, {-2,-2}, {9,9}};const offsetPairType westLeft[]={{2,0}, {2,-1}, {9,9}};const offsetPairType westRight[]={{-2,0}, {-2,-1}, {9,9}};const offsetPairType westProx[]= {{1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {9,9}};

/* Macro Function Definitions */

#define getSRand()((float)rand() / (float)RAND_MAX)#define getRand(x)(int)((x) * getSRand())

#define getWeight()(getRand(9)-1)

/* Parameters that can be adjusted */

#define MAX_FOOD_ENERGY15#define MAX_ENERGY60#define REPRODUCE_ENERGY0.9

#define MAX_AGENTS36

#define MAX_PLANTS35

#define MAX_GRID30

#define MAX_STEPS1000000

#endif /* __COMMON_H */

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch07/main.c

/* * Artificial Life Simulation Functions * * ./software/ch7/main.c * * [email protected] * */

#include #include #include #include #include #include "common.h"

int landscape[3][MAX_GRID][MAX_GRID];

agentType agents[MAX_AGENTS];int agentCount = 0;int agentTypeCounts[2]={0,0};int agentMaxAge[2]={0,0};int agentBirths[2]={0,0};int agentDeaths[2]={0,0};agentType *agentMaxPtr[2];int agentTypeReproductions[2]={0,0};agentType bestAgent[2];

int agentMaxGen[2]={0,0};

plantType plants[MAX_PLANTS];int plantCount = 0;

/* Command line parameters */int seedPopulation = 0;int emitRuntimeTrend = 0;int noGrow = 0;int carn2Plant = 0;int noRepro = 0;int step = 0;

#define AGENTS"agents.dat"#define STATS"stats.dat"#define RUNTIME"runtime.dat"

/* * findEmptySpot() * * Given a pointer to an agent, find an empty spot for the agent within * its particular type plane. * */

void findEmptySpot( agentType *agent ){ agent->location.x = -1; agent->location.y = -1;

while (1) {

agent->location.x = getRand(MAX_GRID); agent->location.y = getRand(MAX_GRID);

if (landscape[agent->type][agent->location.y][agent->location.x] == 0) break;

}

agent->direction = getRand(MAX_DIRECTION); landscape[agent->type][agent->location.y][agent->location.x]++;

return;}

/* * initAgent() * * Initialize the agent passed by reference. * */

void initAgent( agentType *agent ){ int i;

agent->energy = (MAX_ENERGY / 2); agent->age = 0; agent->generation = 1;

agentTypeCounts[agent->type]++;

findEmptySpot( agent );

if (seedPopulation == 0) { for (i = 0 ; i < (MAX_INPUTS * MAX_OUTPUTS) ; i++) { agent->weight_oi[i] = getWeight(); }

for (i = 0 ; i < MAX_OUTPUTS ; i++) { agent->biaso[i] = getWeight(); } }

return;}

/* * growPlant() * * Grow a single plant using the index into the plants array. * */

void growPlant( int i ){ int x,y;

while (1) {

x = getRand(MAX_GRID); y = getRand(MAX_GRID);

if (landscape[PLANT_PLANE][y][x] == 0) {

plants[i].location.x = x; plants[i].location.y = y; landscape[PLANT_PLANE][y][x]++; break;

}

}

return;}

/* * init() * * This is the overall initialization routine for the simulation. It * initialize the plants and agents. If the population is not being * seeded, the agents are all created randomly. Otherwise, the agents * are not random but instead read from the file. * */

void init( void ){

/* Initialize the landscape */ bzero( (void *)landscape, sizeof(landscape) );

bzero( (void *)bestAgent, sizeof(bestAgent) );

/* Initialize the plant plane */ for (plantCount = 0 ; plantCount < MAX_PLANTS ; plantCount++) { growPlant( plantCount ); }

if (seedPopulation == 0) {

/* Randomly initialize the Agents */ for (agentCount = 0 ; agentCount < MAX_AGENTS ; agentCount++) {

if (agentCount < (MAX_AGENTS / 2)) { agents[agentCount].type = TYPE_HERBIVORE; } else { agents[agentCount].type = TYPE_CARNIVORE; }

initAgent( &agents[agentCount] );

}

} else {

/* In this case, we're seeding the population with the agents stored * within the agents.dat file. */

FILE *fp; int offset;

/* Try to seed the population from a file */ fp = fopen(AGENTS, "r");

fread( &bestAgent[0], sizeof( agentType ), 1, fp); fread( &bestAgent[1], sizeof( agentType ), 1, fp);

for (agentCount = 0 ; agentCount < MAX_AGENTS ; agentCount++) {

if (agentCount < MAX_AGENTS / 2) offset = 0; else offset = 1;

memcpy( (void *)&agents[agentCount], (void *)&bestAgent[offset], sizeof(agentType) ); findEmptySpot( &agents[agentCount] );

agents[agentCount].energy = MAX_ENERGY;

agentTypeCounts[agents[agentCount].type]++;

}

}

return;}

/* * emitLandscape() * * This function emits the landscape to the terminal. To slow the display * down, a busy loop is provided at the end. The termination value may be * changed depending upon the speed of your system. * */

void emitLandscape( void ){ int x, y; volatile int i;

system("clear");

for (y = 0 ; y < MAX_GRID ; y++) {

printf("\n%2d : ", y);

for (x = 0 ; x < MAX_GRID ; x++) {

if (landscape[CARN_PLANE][y][x] != 0) printf("C "); else if (landscape[HERB_PLANE][y][x] != 0) printf("H "); else if (landscape[PLANT_PLANE][y][x] != 0) printf("P "); else printf(" ");

}

}

/* Slow down, so that we can watch the behavior */ for (i = 0 ; i < 10000000 ; i++);

return;}

/* * clip() * * Clip the coordinate to provide the toroid. * */

int clip( int z ){ if (z > MAX_GRID-1) z = (z % MAX_GRID); else if (z < 0) z = (MAX_GRID + z); return z;}

/* * percept() * * Calculate the values of the input vector for the neural network. * */

void percept( int x, int y, short *inputs, const offsetPairType *offsets, int neg ){ int plane, i; int xoff, yoff;

for (plane = HERB_PLANE ; plane direction ) {

case NORTH: if (action == ACTION_TURN_LEFT) agent->direction = WEST; else agent->direction = EAST; break;

case SOUTH: if (action == ACTION_TURN_LEFT) agent->direction = EAST; else agent->direction = WEST; break;

case EAST: if (action == ACTION_TURN_LEFT) agent->direction = NORTH; else agent->direction = SOUTH; break;

case WEST: if (action == ACTION_TURN_LEFT) agent->direction = SOUTH; else agent->direction = NORTH; break;

}

return;}

/* * move() * * Implements the move function. The offsets vector is used to * determine the new coordinates for an agent based upon its * current coordinates and facing (direction). * */

void move( agentType *agent ){ const offsetPairType offsets[4]={{-1,0},{1,0},{0,1},{0,-1}};

landscape[agent->type][agent->location.y][agent->location.x]--;

agent->location.x = clip( agent->location.x + offsets[agent->direction].x_offset ); agent->location.y = clip( agent->location.y + offsets[agent->direction].y_offset );

landscape[agent->type][agent->location.y][agent->location.x]++;

return;}

/* * killAgent() * * Kill the agent passed by reference to the function. The agent may have * died because of starvation, or because it was eaten by a predator. * Before the agent is removed, it is checked to see if it was the longest * living agent (of the particular type), and if so is saved. If space is * available for a new agent (< 50% maximum for the agent type), then a * new agent is created. * */

void killAgent( agentType *agent ){ agentDeaths[agent->type]++;

/* Death came to this agent (or it was eaten)... */ landscape[agent->type][agent->location.y][agent->location.x]--; agentTypeCounts[agent->type]--;

if (agent->age > bestAgent[agent->type].age) { memcpy( (void *)&bestAgent[agent->type], (void *)agent, sizeof(agentType) ); }

if (carn2Plant && (agent->type == TYPE_CARNIVORE)) {

if (landscape[PLANT_PLANE][agent->location.y][agent->location.x] == 0) {

int i;

for (i = 0 ; i < MAX_PLANTS ; i++) { if (plants[i].location.x == -1) break; }

if (i < MAX_PLANTS) {

plants[i].location.x = agent->location.x; plants[i].location.y = agent->location.y; landscape[PLANT_PLANE][agent->location.y][agent->location.x]++;

}

agent->location.x = -1; agent->location.y = -1;

}

}

/* 50% of the agent spots are reserved for asexual reproduction. * If we fall under this, we create a new random agent. */ if (agentTypeCounts[agent->type] < (MAX_AGENTS / 4)) {

if (seedPopulation == 0) {

/* Create a new agent */ initAgent( agent );

} else {

agent->location.x = -1; agent->location.y = -1; agent->type = TYPE_DEAD;

}

} else {

agent->location.x = -1; agent->location.y = -1; agent->type = TYPE_DEAD;

}

return;}

/* * reproduceAgent() * * An agent has reached the energy level needed for reproduction. An agent * is only permitted to reproduce if space is available for the new agent. * The child agent is a copy of the parent, except that one of the weights * of the neural network is mutated. * */

void reproduceAgent( agentType *agent ){ agentType *child; int i;

/* Don't allow an agent type to occupy more than half of the available * agent slots. */ if ( agentTypeCounts[agent->type] < (MAX_AGENTS / 2)) {

/* Find an empty spot and copy the agent, mutating one of the * weights or biases. */

for (i = 0 ; i < MAX_AGENTS ; i++) { if (agents[i].type == TYPE_DEAD) break; }

if (i < MAX_AGENTS) {

child = &agents[i];

memcpy( (void *)child, (void *)agent, sizeof(agentType) );

findEmptySpot( child );

if (getSRand() weight_oi[getRand(TOTAL_WEIGHTS)] = getWeight(); }

child->generation = child->generation + 1; child->age = 0;

if (agentMaxGen[child->type] < child->generation) { agentMaxGen[child->type] = child->generation; }

/* Reproducing halves the parent's energy */ child->energy = agent->energy = (MAX_ENERGY / 2);

agentTypeCounts[child->type]++; agentTypeReproductions[child->type]++;

}

}

return;}

/* * chooseObject() * * Given a plane and a set of coordinates, find an object on that plane * within the proximity of the agent (based upon offsets and neg). If * an object is found, a value of 1 is returned with the object's * coordinates in ox/oy. Otherwise, 0 is returned. * */

int chooseObject( int plane, int ax, int ay, const offsetPairType *offsets, int neg, int *ox, int *oy ){ int xoff, yoff, i=0;

while (offsets[i].x_offset != 9) {

xoff = ax + (offsets[i].x_offset * neg); yoff = ay + (offsets[i].y_offset * neg);

xoff = clip( xoff ); yoff = clip( yoff );

if (landscape[plane][yoff][xoff] != 0) { *ox = xoff; *oy = yoff; return 1; }

i++;

}

return 0;}

/* * eat() * * This function implements the eat action for agents. The agent has * a given direction, and based upon this direction, the chooseObject * function is called to identify an object that can be eaten. If an * object is found to be eaten, the energy level is checked to see if * asexual reproduction is permitted. When a plant is eaten by an * herbivore, the growPlant function is called to grow a new plant. * Similarly, if an herbivore is eaten by a carnivore, the herbivore * is killed and possible replaced based upon the current number of * herbivores in the environment. * */

void eat( agentType *agent ){ int plane=0, ax, ay, ox, oy, ret=0;

if (agent->type == TYPE_CARNIVORE) plane = HERB_PLANE; else if (agent->type == TYPE_HERBIVORE) plane = PLANT_PLANE;

ax = agent->location.x; ay = agent->location.y;

switch( agent->direction ) {

case NORTH: ret = chooseObject( plane, ax, ay, northProx, 1, &ox, &oy ); break;

case SOUTH: ret = chooseObject( plane, ax, ay, northProx, -1, &ox, &oy ); break;

case WEST: ret = chooseObject( plane, ax, ay, westProx, 1, &ox, &oy ); break;

case EAST: ret = chooseObject( plane, ax, ay, westProx, -1, &ox, &oy ); break;

}

/* Found an object -- eat it! */ if (ret) {

int i;

if (plane == PLANT_PLANE) {

for (i = 0 ; i < MAX_PLANTS ; i++) { if ((plants[i].location.x == ox) && (plants[i].location.y == oy)) break; }

if (i < MAX_PLANTS) { agent->energy += MAX_FOOD_ENERGY; if (agent->energy > MAX_ENERGY) agent->energy = MAX_ENERGY; landscape[PLANT_PLANE][oy][ox]--; if (noGrow == 0) { growPlant( i ); } else { plants[i].location.x = -1; plants[i].location.y = -1; } }

} else if (plane == HERB_PLANE) {

for (i = 0 ; i < MAX_AGENTS ; i++) { if ( (agents[i].location.x == ox) && (agents[i].location.y == oy)) break; }

if (i < MAX_AGENTS) { agent->energy += (MAX_FOOD_ENERGY*2); if (agent->energy > MAX_ENERGY) agent->energy = MAX_ENERGY; killAgent( &agents[i] ); }

}

if (agent->energy > (REPRODUCE_ENERGY * MAX_ENERGY)) { if (noRepro == 0) { reproduceAgent( agent ); agentBirths[agent->type]++; } }

}

return;}

/* * simulateAgent() * * This is the main agent simulation routine. This function performs * the perception phase which fills in the input cells for the agent's * neural network. This is based upon the particular direction of the * agent. The neural network is then forward propogated to determine * the action to be taken. A function is then called based upon the * action selected. The agent's energy is decremented (since all * agent's use energy while they are alive). If the agent's energy * falls to or below zero, the agent is killed. * */

void simulateAgent( agentType *agent ){ int x, y; int out, in; int largest, winner;

x = agent->location.x; y = agent->location.y;

/* Determine inputs for the agent neural network */ switch( agent->direction ) {

case NORTH: percept( x, y, &agent->inputs[HERB_FRONT], northFront, 1 ); percept( x, y, &agent->inputs[HERB_LEFT], northLeft, 1 ); percept( x, y, &agent->inputs[HERB_RIGHT], northRight, 1 ); percept( x, y, &agent->inputs[HERB_PROXIMITY], northProx, 1 ); break;

case SOUTH: percept( x, y, &agent->inputs[HERB_FRONT], northFront, -1 ); percept( x, y, &agent->inputs[HERB_LEFT], northLeft, -1 ); percept( x, y, &agent->inputs[HERB_RIGHT], northRight, -1 ); percept( x, y, &agent->inputs[HERB_PROXIMITY], northProx, -1 ); break;

case WEST: percept( x, y, &agent->inputs[HERB_FRONT], westFront, 1 ); percept( x, y, &agent->inputs[HERB_LEFT], westLeft, 1 ); percept( x, y, &agent->inputs[HERB_RIGHT], westRight, 1 ); percept( x, y, &agent->inputs[HERB_PROXIMITY], westProx, 1 ); break;

case EAST: percept( x, y, &agent->inputs[HERB_FRONT], westFront, -1 ); percept( x, y, &agent->inputs[HERB_LEFT], westLeft, -1 ); percept( x, y, &agent->inputs[HERB_RIGHT], westRight, -1 ); percept( x, y, &agent->inputs[HERB_PROXIMITY], westProx, -1 ); break;

}

/* Forward propogate the inputs through the neural network */ for ( out = 0 ; out < MAX_OUTPUTS ; out++ ) {

/* Initialize the output node with the bias */ agent->actions[out] = agent->biaso[out];

/* Multiply the inputs by the weights for this output node */ for ( in = 0 ; in < MAX_INPUTS ; in++ ) {

agent->actions[out] += ( agent->inputs[in] * agent->weight_oi[(out * MAX_INPUTS)+in] );

}

}

largest = -9; winner = -1;

/* Select the largest node (winner-takes-all network) */ for ( out = 0 ; out < MAX_OUTPUTS ; out++ ) { if (agent->actions[out] >= largest) { largest = agent->actions[out]; winner = out; } }

/* Perform Action */ switch( winner ) {

case ACTION_TURN_LEFT: case ACTION_TURN_RIGHT: turn( winner, agent ); break;

case ACTION_MOVE: move( agent ); break;

case ACTION_EAT: eat( agent ); break;

}

/* Consume some amount of energy */ if (agent->type == TYPE_HERBIVORE) { agent->energy -= 2; } else { agent->energy -= 1; }

/* If energy falls to or below zero, the agent dies. Otherwise, we * check to see if the agent has lived longer than any other agent * of the particular type. */ if (agent->energy age++; if (agent->age > agentMaxAge[agent->type]) { agentMaxAge[agent->type] = agent->age; agentMaxPtr[agent->type] = agent; } }

return;}

/* * simulate() * * The simulate function permits each agent to be simulated for one * iteration. Herbivores are permitted to perform one iteration first * and then the carnivores. * */

void simulate( void ){ int i, type;

/* Simulate the herbivores first, then the carnivores */ for (type = TYPE_HERBIVORE ; type age > bestAgent[i].age) { memcpy( (void *)&bestAgent[i], (void *)agentMaxPtr[i], sizeof( agentType ) ); } }

/* Write the two best agents to a file */ fp = fopen(AGENTS, "wb"); for (i = 0 ; i < 2 ; i++) { fwrite( &bestAgent[i], sizeof( agentType ), 1, fp); } fclose(fp);}

/* * emitRuntimeTrend2File * * This function emits runtime trend information to the runtime.dat * file. This data is specific to playback of successful agents * after evolution is complete. * */

void emitRuntimeTrend2File( FILE *rfp, int i ){ int j;

fprintf(rfp, "%d %d %d %d %d\n", i, agentBirths[0], agentBirths[1] , agentDeaths[0], agentDeaths[1] ); fflush(rfp);

for (j = 0 ; j < 2 ; j++) { agentBirths[j] = 0; agentDeaths[j] = 0; }

}

int main( int argc, char *argv[] ){ int i, c; FILE *fp = NULL, *rfp = NULL;

seedPopulation = 0;

/* * Parse all options from the command line. */ while (1) {

if ((c = getopt( argc, argv, "prgcnsh")) > 0) {

switch( c ) {

case 'p': /* Playback mode */ seedPopulation = 1; break;

case 'r': /* Save Runtime trend data (useful in playback) */ emitRuntimeTrend = 1; break;

case 'g': /* Don't Grow plants */ noGrow = 1; break;

case 'c': /* Carnivores become Plants after death */ carn2Plant = 1; break;

case 'n': /* No reproduction */ noRepro = 1; break;

case 's': /* Manual step */ step = 1; break;

case 'h': emitHelp( argv[0] ); break;

}

} else break;

}

/* Seed the random number generator */ srand( time(NULL) );

/* If we're in playback mode, don't do stats */ if (seedPopulation == 0) { fp = fopen(STATS, "w"); }

if (emitRuntimeTrend == 1) { rfp = fopen(RUNTIME, "w"); }

/* Initialize the simulation */ init();

/* Main loop for the simulation. */ for (i = 0 ; i < MAX_STEPS ; i++) {

/* Emit the landscape to the terminal if we're in playback mode. */ if (seedPopulation) emitLandscape();

/* Await user return before continuing */ if (step) { (void)getchar(); }

/* Simulate each agent for one time step */ simulate();

/* Emit data at some low rate */ if (seedPopulation == 0) { if ((i % 100) == 0) { emitTrend2File( fp, i ); } } else { if ((agentTypeCounts[0] == 0) && (agentTypeCounts[1] == 0)) break; }

/* For playback trend data, emit each time step */ if (emitRuntimeTrend) { emitRuntimeTrend2File( rfp, i ); }

}

if (seedPopulation == 0) { fclose(fp); emitAgents2File(); }

if (emitRuntimeTrend) { fclose(rfp); }

return 0;}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch07/Makefile

## Makefile for emhttp#

CC = gccCFLAGS = -g -O2

OBJS =main.o

all:sim

sim: $(OBJS)$(CC) -o sim $(OBJS)

sim: main.c

.c.o:$(CC) $(CFLAGS) -Wall -c $(add (sensor-active none)); consequents(add (sensor-working sensor1))(add (sensor-working sensor2))(add (mode normal))(enable (timer 1 10))(disable (self))(print ("default rule fired!")))

;; Define rule-set;

(defrule sensor-working(sensor-working ?)(sensor-failed ?)=>(delete (sensor-working ?)))

(defrule none-active(sensor-active ?)(sensor-failed ?)=>(delete (sensor-active ?))(add (sensor-active none)))

(defrule make-working(sensor-active none)(sensor-working ?)=>(add (sensor-active ?))(delete (mode failure))(add (mode normal))(delete (sensor-active none)))

(defrule failure(mode normal)(sensor-active none)(sensor-failed sensor1)(sensor-failed sensor2)=>(add (mode failure))(delete (mode safe))(delete (mode normal)))

; Use triggers to simulate failures of sensors...(defrule trigger1(timer-triggered 1)=>(print ("Sensor 1 failure.\n"))(add (sensor-failed sensor1))(enable (timer 2 10))(delete (timer-triggered 1)))

(defrule trigger2(timer-triggered 2)=>(print ("Sensor 2 failure.\n"))(add (sensor-failed sensor2))(enable (timer 3 10))(delete (timer-triggered 2)))

(defrule trigger3(timer-triggered 3)=>(print ("Sensor 1 is now working.\n"))(add (sensor-working sensor1))(delete (sensor-failed sensor1))(enable (timer 4 10))(delete (timer-triggered 3)))

(defrule trigger4(timer-triggered 4)=>(print ("Sensor 2 is now working.\n"))(add (sensor-working sensor2))(delete (sensor-failed sensor2))(enable (timer 1 10))(delete (timer-triggered 4)))

software/ch08/interp.c

/* * Rules based system interpreter * * ./software/ch8/interp.c * * [email protected] * */

#include #include "common.h"

extern ruleType ruleSet[MAX_RULES];

/* * interpret() * * Walk through the active rules looking for a rule that can fire. * */

void interpret( void ){ int rule; int fired = 0;

extern int checkRule( int ); extern int debug;

for (rule = 0 ; rule < MAX_RULES ; rule++) {

fired = 0;

if (ruleSet[rule].active) {

fired = checkRule( rule );

/* If a rule had some effect on working memory, exit, otherwise test * another rule. */ if (fired) break;

}

}

if (debug) { if (fired) printf("Fired rule %s (%d)\n", ruleSet[rule].ruleName, rule); }

return;}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted without fee provided * that the following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. Neither the name of Charles River Media nor the names of * its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTORS * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */

software/ch08/main.c

/* * Rules-based system main * * ./software/ch8/main.c * * [email protected] * */

#include #include #include #include "common.h"

memoryElementType workingMemory[MAX_MEMORY_ELEMENTS];int memIndex = 0;

ruleType ruleSet[MAX_RULES];int ruleIndex;

extern timerType timers[MAX_TIMERS];

int endRun = 0, debug;

/* * printStructure() * * Debug function to emit the set of parsed rules. * */

void printStructure( void ){ memoryElementType *ptr; int i;

printf("Parsed %d rules\n", ruleIndex);

for (i = 0 ; i < MAX_RULES ; i++) {

if (ruleSet[i].active) {

printf("Rule %d :\n", i); printf("Antecedents : \n"); ptr = ruleSet[i].antecedent; while (ptr) { printf(" %s\n", ptr->element); ptr = ptr->next; } printf("Consequents : \n"); ptr = ruleSet[i].consequent; while (ptr) { printf(" %s\n", ptr->element); ptr = ptr->next; } printf("\n");

} }}

/* * printWorkingMemory() * * Debug function to emit the current set of facts from the * working memory. * */

void printWorkingMemory( void ){ int slot;

printf("\tWorking Memory:\n");

for (slot = 0 ; slot < MAX_MEMORY_ELEMENTS ; slot++) {

if (workingMemory[slot].active) {

printf("\t\t%s\n", workingMemory[slot].element);

}

}

printf("\n");}

/* * emitHelp() * * Emit the command-line help. * */

void emitHelp( void ){ printf("\n\trbs -r [-hd]\n\n"); printf("\t\t -r specify the rules file\n"); printf("\t\t -d debug mode\n"); printf("\t\t -h this help\n\n"); exit(0);}

/* * main() * * Main function for the forward-chaining rules-based system. * */

int main( int argc, char *argv[] ){ int opt, ret; char inpfile[80]={0};

extern void processTimers( void ); extern int parseFile( char * ); extern void interpret( void );

debug = 0;

while ((opt = getopt(argc, argv, "hdr:")) != -1) {

switch( opt ) {

case 'r': strcpy(inpfile, optarg); break;

case 'd': debug = 1; printf("Debugging enabled\n"); break;

case 'h': emitHelp(); break;

}

}

if (inpfile[0] == 0) emitHelp();

bzero( (void *)workingMemory, sizeof(workingMemory) ); bzero( (void *)ruleSet, sizeof(ruleSet) ); bzero( (void *)timers, sizeof(timers) );

ret = parseFile( inpfile );

if (ret < 0) { printf("\nCould not open file, or parse error\n\n"); exit(0); }

// printStructure();

while (1) {

interpret();

if (debug) { printWorkingMemory(); }

processTimers();

if (endRun) break;

sleep(1);

}

return 0;}

/* * Copyright (c) 2003 Charles River Media. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, is hereby granted withou