Программирование ИИ в приложениях(тексты примеров)
Post on 08-Dec-2016
263 views
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( ¤t ); computeEnergy( ¤t ); best.energy = 100.0;
copySolution( &working, ¤t);
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( ¤t, &working );
if (current.energy < best.energy) { copySolution( &best, ¤t ); solution = 1; }
} else {
copySolution( &working, ¤t);
}
}
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