Created
November 26, 2010 06:33
-
-
Save anonymous/716352 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include "ants.h" | |
void runSimulation(int steps, int numAnts, int pathLength, double bias, double decay){ | |
// Allocate a block of Nodes and Ants | |
// Assuming pathLength of 50, it'd be as follows: | |
// Node[0..49] : path to food A (A) | |
// Node[50..99] : path to food B (B) | |
// Node[100] : Center / Colony | |
// Node[101] : Food A | |
// Node[102] : Food B | |
FILE* file = fopen("ants.dat", "a"); | |
Node *nodes = calloc(pathLength * 2 + 3, sizeof(Node)); | |
Ant *ants = calloc(numAnts, sizeof(Ant)); | |
/* Setup */ | |
Node *center = &nodes[2*pathLength]; center->type = CenterNode; | |
Node *foodA = &nodes[2*pathLength + 1]; foodA->type = UnaryNode; | |
Node *foodB = &nodes[2*pathLength + 2]; foodB->type = UnaryNode; | |
Node *currentNode, *prevNode; | |
for (int path = 0; path < 2; path++) { | |
// Start each path with the center node | |
currentNode = &nodes[path*pathLength + 0]; | |
currentNode->type = BinaryNode; | |
// Start the series on the correct branch | |
switch (path) { | |
case 0: // A | |
center->pathA = currentNode; | |
currentNode->prev = center; | |
break; | |
case 1: // B | |
center->pathB = currentNode; | |
currentNode->prev = center; | |
break; | |
} | |
prevNode = currentNode; | |
// Start at 1 since 1st node is already connected | |
for (int i = 1; i < pathLength; i++) { | |
// Set all nodes along each path as Binary | |
currentNode = &nodes[path*pathLength + i]; | |
currentNode->type = BinaryNode; | |
// Link nodes | |
currentNode->prev = prevNode; | |
prevNode->next = currentNode; | |
// Assign previous to next | |
prevNode = currentNode; | |
} | |
// End each path with the appropriate endpoint | |
switch (path) { | |
case 0: // A | |
prevNode->next = foodA; | |
foodA->prev = prevNode; | |
break; | |
case 1: // B | |
prevNode->next = foodB; | |
foodB->prev = prevNode; | |
break; | |
} | |
} | |
// Set all ants to start at colony | |
for (int i = 0; i < numAnts; i++) { | |
ants[i].currentNode = center; | |
} | |
// Seed the random number generator | |
srand(time(NULL)); | |
// Iterate through time steps | |
int antsOnA = 0; | |
for (int t = 0; t < steps; t++) { | |
antsOnA = 0; | |
/* Decay Pheromone */ | |
for (int path = 0; path < 2; path++) { | |
Node *nodeToDecay = (path == 0)?(center->prev):(center->next); | |
while (nodeToDecay->type != UnaryNode) { | |
nodeToDecay->pheromone -= nodeToDecay->pheromone * decay; | |
nodeToDecay = nodeToDecay->next; | |
} | |
} | |
/* Move Ants */ | |
for (int a = 0; a < numAnts; a++) { | |
Ant *ant = &ants[a]; | |
if (ant->hasFood == true) { | |
/* Exploitation Movement : | |
* 1) If the ant has food, it should proceed directly back to the colony. | |
* 2) Once it reaches the center, it will lose its food and return to Scavenging Movement | |
*/ | |
ant->currentNode = ant->currentNode->prev; | |
} | |
else { | |
/* Scavenging Movement | |
* 1) At each decision point, direction is biased based on pheromone | |
* 2) The food sources are infinitely attractive (ant will always enter it if it has food, and is next to it) | |
*/ | |
switch (ant->currentNode->type) { | |
// NOTE: 'prev' is inward, 'next' is outward. | |
// A <========== C ===========> B | |
case UnaryNode: {// food A or B (only one movement options) | |
ant->currentNode = ant->currentNode->prev; | |
break; | |
} | |
case CenterNode: | |
// In the event of the ant being on the colony, the logic is identical to any other binary node. | |
// It should be noted that "next" is equivalent to "pathA" and "prev" is equivalent to "pathB" | |
case BinaryNode: { // path (two options, pheromone biased) | |
// (not using) 50/50 behavior | |
//ant->currentNode = (rand() % 2)?(ant->currentNode->next):(ant->currentNode->prev); break; | |
// Food sources infinitely attractive if they have food | |
if ((ant->currentNode->next == foodA && foodAtA) || (ant->currentNode->next == foodB && foodAtB)) { | |
ant->currentNode = ant->currentNode->next; | |
break; | |
} | |
// Normal case (biased by pheromone) | |
double nextPheromone = ant->currentNode->next->pheromone + 1; | |
double prevPheromone = ant->currentNode->prev->pheromone + 1; | |
double random = ((nextPheromone + prevPheromone) * rand()) / (RAND_MAX + 1.0); | |
//double random = ((double)rand()/RAND_MAX) * (nextPheromone + prevPheromone); | |
if (random <= nextPheromone) { | |
ant->currentNode = ant->currentNode->next; | |
} | |
else { | |
ant->currentNode = ant->currentNode->prev; | |
} | |
break; | |
} | |
default: | |
perror("Error: Invalid Node"); | |
exit(-1); | |
break; | |
} | |
} | |
/* Toggle food */ | |
if (ant->currentNode == foodA && foodAtA) { | |
ant->hasFood = true; | |
} | |
if (ant->currentNode == foodB && foodAtB) { | |
ant->hasFood = true; | |
} | |
if (ant->currentNode == center) { | |
ant->hasFood = false; | |
} | |
/* Deposit Pheromone */ | |
if (ant->hasFood) { | |
ant->currentNode->pheromone += 1; | |
} | |
/* Tally ants on current branch */ | |
Node *tallyNode = ant->currentNode; | |
if (tallyNode == center) { | |
continue; | |
} | |
while (tallyNode->type != UnaryNode) { | |
tallyNode = tallyNode->next; | |
} | |
if (tallyNode == foodA) { | |
antsOnA++; | |
} | |
} // a | |
} // t | |
// Output ants on path, and pheromone decay rate | |
fprintf(file, "%f %d\n", decay, antsOnA); | |
free(nodes); | |
free(ants); | |
fclose(file); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _ANTS_H_ | |
#define _ANTS_H_ | |
// Boolean data type! | |
#import <stdbool.h> | |
#pragma mark Data Types | |
typedef enum { | |
NullaryNode = 0, | |
UnaryNode = 1, | |
BinaryNode = 2, | |
CenterNode = 3 | |
} NodeType; | |
#pragma mark Structures | |
// Base Node | |
typedef struct node_struct Node; | |
struct node_struct { | |
double pheromone; | |
NodeType type; | |
union { | |
struct { | |
Node *next; | |
Node *prev; | |
}; | |
struct { | |
Node *pathA; | |
Node *pathB; | |
}; | |
}; | |
}; | |
const static int foodAtA = true; | |
const static int foodAtB = true; | |
typedef struct ant_struct Ant; | |
struct ant_struct { | |
bool hasFood; | |
Node *currentNode; | |
}; | |
#pragma mark Functions | |
void runSimulation(int steps, int numAnts, int pathLength, double bias, double decay); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment