PageRenderTime 55ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/mona/src/maze_mouse/evolveMouse.cpp

#
C++ | 1545 lines | 1217 code | 197 blank | 131 comment | 209 complexity | 90574da7ec9a1076044091d5b4dca42c MD5 | raw file
  1. // For conditions of distribution and use, see copyright notice in muzz.hpp
  2. // Evolve maze-learning mouse by mutating and recombining brain parameters.
  3. #include "evolveMouse.hpp"
  4. // Version (SCCS "what" format).
  5. const char *MouseEvolveVersion = MOUSE_EVOLVE_VERSION;
  6. // Print version.
  7. void
  8. printEvolveVersion(FILE *out = stdout)
  9. {
  10. fprintf(out, "%s\n", &MouseEvolveVersion[5]);
  11. }
  12. // Usage.
  13. char *Usage[] =
  14. {
  15. (char *)"To run:",
  16. (char *)" evolve_mouse",
  17. (char *)" [-generations <evolution generations>]",
  18. (char *)" [-numMazeTests (number of maze tests)]",
  19. (char *)" [-numDoorTrainingTrials (number of door association training trials)]",
  20. (char *)" [-numMazeTrainingTrials (number of training trials per maze test)]",
  21. (char *)" [-mutationRate <mutation rate>]",
  22. (char *)" [-randomSeed <random seed> (for new run)]",
  23. (char *)" [-print (print mouse brain parameters)]",
  24. (char *)" [-input <evolution input file name>]",
  25. (char *)" [-output <evolution output file name>]",
  26. (char *)" [-logfile <log file name>]",
  27. (char *)" [-ignoreInterrupts (ignore interrupts)]",
  28. #ifdef WIN32
  29. (char *)" [-attachConsole (attach to console)]",
  30. #endif
  31. (char *)"To print version:",
  32. (char *)" evolve_mouse",
  33. (char *)" [-version (print version)]",
  34. NULL
  35. };
  36. // Print and log error.
  37. void printError(char *buf)
  38. {
  39. fprintf(stderr, "%s\n", buf);
  40. if (Log::LOGGING_FLAG == LOG_TO_FILE)
  41. {
  42. sprintf(Log::messageBuf, "%s", buf);
  43. Log::logError();
  44. }
  45. }
  46. // Print and log information.
  47. void printInfo(char *buf)
  48. {
  49. fprintf(stderr, "%s\n", buf);
  50. if (Log::LOGGING_FLAG == LOG_TO_FILE)
  51. {
  52. sprintf(Log::messageBuf, "%s", buf);
  53. Log::logInformation();
  54. }
  55. }
  56. // Print usage.
  57. void printUsage()
  58. {
  59. for (int i = 0; Usage[i] != NULL; i++)
  60. {
  61. printInfo(Usage[i]);
  62. }
  63. }
  64. // Evolution generation.
  65. int Generation = 0;
  66. // Generations to run.
  67. int Generations = -1;
  68. // Number of maze tests.
  69. int NumMazeTests = DEFAULT_NUM_MAZE_TESTS;
  70. // Number of door association training trials.
  71. int NumDoorTrainingTrials = DEFAULT_NUM_DOOR_TRAINING_TRIALS;
  72. // Number of maze training trials.
  73. int NumMazeTrainingTrials = DEFAULT_NUM_MAZE_TRAINING_TRIALS;
  74. // Are maze room doors all visible?
  75. // Some of these doors are blocked.
  76. bool SeeAllMazeDoors = true;
  77. // Mutation rate.
  78. PROBABILITY MutationRate = DEFAULT_MUTATION_RATE;
  79. // Random numbers.
  80. RANDOM RandomSeed = INVALID_RANDOM;
  81. Random *Randomizer = NULL;
  82. // Print mouse brain parameters.
  83. bool Print = false;
  84. // Population file names.
  85. char *InputFileName = NULL;
  86. char *OutputFileName = NULL;
  87. // Room types.
  88. #define START_ROOM 0
  89. #define BEGIN_MAZE 1
  90. #define MAZE_ROOM 2
  91. #define END_MAZE 3
  92. #define GOAL_ROOM 4
  93. #define DEAD_ROOM 5
  94. // Responses.
  95. #define TAKE_DOOR_0 0
  96. #define TAKE_DOOR_1 1
  97. #define TAKE_DOOR_2 2
  98. #define WAIT 3
  99. #define HOP 4
  100. // Cheese need and goal.
  101. #define CHEESE_NEED 1.0
  102. #define CHEESE_GOAL 0.5
  103. // Maze-learning task.
  104. int DoorAssociations[3];
  105. vector<vector<int> > MazePaths;
  106. // Maze room.
  107. class Room
  108. {
  109. public:
  110. int type;
  111. int cx;
  112. int cy;
  113. bool hasCheese;
  114. vector<Room *> doors;
  115. Room(int type, int cx, int cy)
  116. {
  117. this->type = type;
  118. this->cx = cx;
  119. this->cy = cy;
  120. }
  121. // Set room doors to other rooms.
  122. void setDoors(vector<Room *>& doors)
  123. {
  124. this->doors = doors;
  125. }
  126. };
  127. // Maze.
  128. vector<Room *> maze[7];
  129. int beginMazeIndex;
  130. int endMazeIndex;
  131. // Mouse position.
  132. int mouseX;
  133. int mouseY;
  134. // Build maze.
  135. void buildMaze()
  136. {
  137. vector<Room *> doors;
  138. maze[0].resize(3);
  139. maze[0][1] = new Room(START_ROOM, 0, 1);
  140. maze[0][0] = new Room(START_ROOM, 0, 0);
  141. maze[0][2] = new Room(START_ROOM, 0, 2);
  142. beginMazeIndex = 1;
  143. maze[1].resize(1);
  144. maze[1][0] = new Room(BEGIN_MAZE, 1, 0);
  145. doors.resize(3);
  146. doors[0] = NULL;
  147. doors[1] = NULL;
  148. doors[2] = maze[1][0];
  149. maze[0][0]->setDoors(doors);
  150. doors[0] = NULL;
  151. doors[1] = maze[1][0];
  152. doors[2] = NULL;
  153. maze[0][1]->setDoors(doors);
  154. doors[0] = maze[1][0];
  155. doors[1] = NULL;
  156. doors[2] = NULL;
  157. maze[0][2]->setDoors(doors);
  158. maze[2].resize(3);
  159. maze[2][1] = new Room(MAZE_ROOM, 2, 1);
  160. maze[2][0] = new Room(MAZE_ROOM, 2, 0);
  161. maze[2][2] = new Room(MAZE_ROOM, 2, 2);
  162. doors[0] = maze[2][0];
  163. doors[1] = maze[2][1];
  164. doors[2] = maze[2][2];
  165. maze[1][0]->setDoors(doors);
  166. maze[3].resize(5);
  167. maze[3][2] = new Room(MAZE_ROOM, 3, 2);
  168. maze[3][1] = new Room(MAZE_ROOM, 3, 1);
  169. maze[3][0] = new Room(MAZE_ROOM, 3, 0);
  170. maze[3][3] = new Room(MAZE_ROOM, 3, 3);
  171. maze[3][4] = new Room(MAZE_ROOM, 3, 4);
  172. doors[0] = maze[3][0];
  173. doors[1] = maze[3][1];
  174. doors[2] = maze[3][2];
  175. maze[2][0]->setDoors(doors);
  176. doors[0] = maze[3][1];
  177. doors[1] = maze[3][2];
  178. doors[2] = maze[3][3];
  179. maze[2][1]->setDoors(doors);
  180. doors[0] = maze[3][2];
  181. doors[1] = maze[3][3];
  182. doors[2] = maze[3][4];
  183. maze[2][2]->setDoors(doors);
  184. maze[4].resize(3);
  185. maze[4][1] = new Room(MAZE_ROOM, 4, 1);
  186. maze[4][0] = new Room(MAZE_ROOM, 4, 0);
  187. maze[4][2] = new Room(MAZE_ROOM, 4, 2);
  188. doors[0] = NULL;
  189. doors[1] = NULL;
  190. doors[2] = maze[4][0];
  191. maze[3][0]->setDoors(doors);
  192. doors[0] = NULL;
  193. doors[1] = maze[4][0];
  194. doors[2] = maze[4][1];
  195. maze[3][1]->setDoors(doors);
  196. doors[0] = maze[4][0];
  197. doors[1] = maze[4][1];
  198. doors[2] = maze[4][2];
  199. maze[3][2]->setDoors(doors);
  200. doors[0] = maze[4][1];
  201. doors[1] = maze[4][2];
  202. doors[2] = NULL;
  203. maze[3][3]->setDoors(doors);
  204. doors[0] = maze[4][2];
  205. doors[1] = NULL;
  206. doors[2] = NULL;
  207. maze[3][4]->setDoors(doors);
  208. endMazeIndex = 5;
  209. maze[5].resize(1);
  210. maze[5][0] = new Room(END_MAZE, 5, 0);
  211. doors[0] = NULL;
  212. doors[1] = NULL;
  213. doors[2] = maze[5][0];
  214. maze[4][0]->setDoors(doors);
  215. doors[0] = NULL;
  216. doors[1] = maze[5][0];
  217. doors[2] = NULL;
  218. maze[4][1]->setDoors(doors);
  219. doors[0] = maze[5][0];
  220. doors[1] = NULL;
  221. doors[2] = NULL;
  222. maze[4][2]->setDoors(doors);
  223. maze[6].resize(3);
  224. maze[6][1] = new Room(GOAL_ROOM, 6, 1);
  225. maze[6][0] = new Room(GOAL_ROOM, 6, 0);
  226. maze[6][2] = new Room(GOAL_ROOM, 6, 2);
  227. doors[0] = maze[6][0];
  228. doors[1] = maze[6][1];
  229. doors[2] = maze[6][2];
  230. maze[5][0]->setDoors(doors);
  231. doors[0] = NULL;
  232. doors[1] = NULL;
  233. doors[2] = NULL;
  234. maze[6][0]->setDoors(doors);
  235. maze[6][1]->setDoors(doors);
  236. maze[6][2]->setDoors(doors);
  237. mouseX = mouseY = 0;
  238. }
  239. // Initialize mouse brain.
  240. void initBrain(Mona *mouse)
  241. {
  242. vector<Mona::SENSOR> goalSensors;
  243. mouse->initNet(5, HOP + 1, 1, Randomizer->RAND());
  244. // Set a long second effect interval
  245. // for a higher level mediator.
  246. mouse->effectEventIntervals[1].resize(2);
  247. mouse->effectEventIntervalWeights[1].resize(2);
  248. mouse->effectEventIntervals[1][0] = 2;
  249. mouse->effectEventIntervalWeights[1][0] = 0.5;
  250. mouse->effectEventIntervals[1][1] = 10;
  251. mouse->effectEventIntervalWeights[1][1] = 0.5;
  252. // Set need and goal for cheese.
  253. mouse->setNeed(0, CHEESE_NEED);
  254. goalSensors.push_back(0.0);
  255. goalSensors.push_back(0.0);
  256. goalSensors.push_back(0.0);
  257. goalSensors.push_back((double)GOAL_ROOM);
  258. goalSensors.push_back(1.0);
  259. mouse->homeostats[0]->addGoal(goalSensors, 0,
  260. Mona::NULL_RESPONSE, CHEESE_GOAL);
  261. }
  262. // Parameter mutator.
  263. class ParmMutator
  264. {
  265. public:
  266. // Probability of random mutation.
  267. static PROBABILITY RANDOM_MUTATION;
  268. typedef enum
  269. {
  270. INTEGER_PARM, FLOAT_PARM, DOUBLE_PARM
  271. }
  272. PARM_TYPE;
  273. PARM_TYPE type;
  274. enum { PARM_NAME_SIZE=50 };
  275. char name[PARM_NAME_SIZE];
  276. void *parm;
  277. double min;
  278. double max;
  279. double delta;
  280. // Constructors.
  281. ParmMutator()
  282. {
  283. type = DOUBLE_PARM;
  284. name[0] = '\0';
  285. parm = NULL;
  286. min = max = delta = 0.0f;
  287. }
  288. ParmMutator(PARM_TYPE type, char *name, void *parm,
  289. double min, double max, double delta)
  290. {
  291. this->type = type;
  292. strncpy(this->name, name, PARM_NAME_SIZE - 1);
  293. this->parm = parm;
  294. this->min = min;
  295. this->max = max;
  296. this->delta = delta;
  297. }
  298. // Mutate parameter.
  299. void mutate()
  300. {
  301. int i;
  302. float f;
  303. double d;
  304. if (!Randomizer->RAND_CHANCE(MutationRate)) { return; }
  305. switch (type)
  306. {
  307. case INTEGER_PARM:
  308. if (Randomizer->RAND_CHANCE(RANDOM_MUTATION))
  309. {
  310. *(int *)parm = (int)Randomizer->RAND_INTERVAL(min, max + 0.99);
  311. }
  312. else
  313. {
  314. i = *(int *)parm;
  315. if (Randomizer->RAND_BOOL())
  316. {
  317. i += (int)delta;
  318. if (i > (int)max) { i = (int)max; }
  319. }
  320. else
  321. {
  322. i -= (int)delta;
  323. if (i < (int)min) { i = (int)min; }
  324. }
  325. *(int *)parm = i;
  326. }
  327. break;
  328. case FLOAT_PARM:
  329. if (Randomizer->RAND_CHANCE(RANDOM_MUTATION))
  330. {
  331. *(float *)parm = (float)Randomizer->RAND_INTERVAL(min, max);
  332. }
  333. else
  334. {
  335. f = *(float *)parm;
  336. if (Randomizer->RAND_BOOL())
  337. {
  338. f += (float)delta;
  339. if (f > (float)max) { f = (float)max; }
  340. }
  341. else
  342. {
  343. f -= (float)delta;
  344. if (f < (float)min) { f = (float)min; }
  345. }
  346. *(float *)parm = f;
  347. }
  348. break;
  349. case DOUBLE_PARM:
  350. if (Randomizer->RAND_CHANCE(RANDOM_MUTATION))
  351. {
  352. *(double *)parm = (double)Randomizer->RAND_INTERVAL(min, max);
  353. }
  354. else
  355. {
  356. d = *(double *)parm;
  357. if (Randomizer->RAND_BOOL())
  358. {
  359. d += delta;
  360. if (d > max) { d = max; }
  361. }
  362. else
  363. {
  364. d -= delta;
  365. if (d < min) { d = min; }
  366. }
  367. *(double *)parm = d;
  368. }
  369. break;
  370. }
  371. }
  372. // Copy parameter from given one.
  373. void copy(ParmMutator *from)
  374. {
  375. switch (type)
  376. {
  377. case INTEGER_PARM:
  378. *(int *)parm = *(int *)from->parm;
  379. break;
  380. case FLOAT_PARM:
  381. *(float *)parm = *(float *)from->parm;
  382. break;
  383. case DOUBLE_PARM:
  384. *(double *)parm = *(double *)from->parm;
  385. break;
  386. }
  387. }
  388. };
  389. PROBABILITY ParmMutator::RANDOM_MUTATION = 0.1;
  390. // Brain parameter mutator.
  391. class BrainParmMutator
  392. {
  393. public:
  394. // Brain.
  395. Mona *brain;
  396. // Parameter mutators.
  397. vector<ParmMutator *> parmMutators;
  398. // Constructor.
  399. BrainParmMutator(Mona *brain)
  400. {
  401. this->brain = brain;
  402. // INITIAL_ENABLEMENT.
  403. ParmMutator *parmMutator =
  404. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"INITIAL_ENABLEMENT",
  405. (void *)&brain->INITIAL_ENABLEMENT, 0.1, 1.0, 0.1);
  406. assert(parmMutator != NULL);
  407. parmMutators.push_back(parmMutator);
  408. // DRIVE_ATTENUATION.
  409. parmMutator =
  410. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"DRIVE_ATTENUATION",
  411. (void *)&brain->DRIVE_ATTENUATION, 0.0, 1.0, 0.1);
  412. assert(parmMutator != NULL);
  413. parmMutators.push_back(parmMutator);
  414. // LEARNING_DECREASE_VELOCITY.
  415. parmMutator =
  416. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"LEARNING_DECREASE_VELOCITY",
  417. (void *)&brain->LEARNING_DECREASE_VELOCITY, 0.1, 0.9, 0.1);
  418. assert(parmMutator != NULL);
  419. parmMutators.push_back(parmMutator);
  420. // LEARNING_INCREASE_VELOCITY.
  421. parmMutator =
  422. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"LEARNING_INCREASE_VELOCITY",
  423. (void *)&brain->LEARNING_INCREASE_VELOCITY, 0.1, 0.9, 0.1);
  424. assert(parmMutator != NULL);
  425. parmMutators.push_back(parmMutator);
  426. // FIRING_STRENGTH_LEARNING_DAMPER.
  427. parmMutator =
  428. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"FIRING_STRENGTH_LEARNING_DAMPER",
  429. (void *)&brain->FIRING_STRENGTH_LEARNING_DAMPER, 0.05, 0.9, 0.05);
  430. assert(parmMutator != NULL);
  431. parmMutators.push_back(parmMutator);
  432. }
  433. // Destructor.
  434. ~BrainParmMutator()
  435. {
  436. for (int i = 0; i < (int)parmMutators.size(); i++)
  437. {
  438. delete parmMutators[i];
  439. }
  440. parmMutators.clear();
  441. }
  442. // Mutate.
  443. void mutate()
  444. {
  445. for (int i = 0; i < (int)parmMutators.size(); i++)
  446. {
  447. parmMutators[i]->mutate();
  448. }
  449. // Initialize brain with new parameters.
  450. initBrain(brain);
  451. }
  452. // Copy parameters from given brain.
  453. void copy(BrainParmMutator *from)
  454. {
  455. for (int i = 0; i < (int)parmMutators.size(); i++)
  456. {
  457. parmMutators[i]->copy(from->parmMutators[i]);
  458. }
  459. // Initialize brain with new parameters.
  460. initBrain(brain);
  461. }
  462. // Randomly merge parameters from given brains.
  463. void meld(BrainParmMutator *from1, BrainParmMutator *from2)
  464. {
  465. for (int i = 0; i < (int)parmMutators.size(); i++)
  466. {
  467. if (Randomizer->RAND_BOOL())
  468. {
  469. parmMutators[i]->copy(from1->parmMutators[i]);
  470. }
  471. else
  472. {
  473. parmMutators[i]->copy(from2->parmMutators[i]);
  474. }
  475. }
  476. // Initialize brain with new parameters.
  477. initBrain(brain);
  478. }
  479. };
  480. // Population member.
  481. class Member
  482. {
  483. public:
  484. static int idDispenser;
  485. int id;
  486. Mona *mouse;
  487. double fitness;
  488. int generation;
  489. // Brain parameter mutator.
  490. BrainParmMutator *brainParmMutator;
  491. // Constructors.
  492. Member(int generation = 0)
  493. {
  494. id = idDispenser;
  495. idDispenser++;
  496. // Create the mouse brain.
  497. mouse = new Mona();
  498. assert(mouse != NULL);
  499. initBrain(mouse);
  500. // Create brain parameter mutator.
  501. brainParmMutator = new BrainParmMutator(mouse);
  502. assert(brainParmMutator != NULL);
  503. brainParmMutator->mutate();
  504. fitness = 0.0;
  505. this->generation = generation;
  506. }
  507. // Destructor.
  508. ~Member()
  509. {
  510. if (brainParmMutator != NULL) { delete brainParmMutator; }
  511. if (mouse != NULL) { delete mouse; }
  512. }
  513. // Evaluate.
  514. // Fitness is determined number of correct tests.
  515. void evaluate()
  516. {
  517. int i, j, k;
  518. vector<int> path;
  519. // Clear brain.
  520. initBrain(mouse);
  521. // Train door associations.
  522. for (i = 0; i < NumDoorTrainingTrials; i++)
  523. {
  524. for (j = 0; j < 3; j++)
  525. {
  526. path.clear();
  527. path.push_back(2 - j);
  528. path.push_back(HOP);
  529. path.push_back(DoorAssociations[j]);
  530. path.push_back(WAIT);
  531. runTrial(0, j, path, true);
  532. }
  533. }
  534. fitness = 0.0;
  535. for (i = 0; i < NumMazeTests; i++)
  536. {
  537. // Train maze path.
  538. for (j = 0; j < NumMazeTrainingTrials; j++)
  539. {
  540. path.clear();
  541. path = MazePaths[i];
  542. path.push_back(WAIT);
  543. runTrial(beginMazeIndex, 0, path, true);
  544. }
  545. // Test maze.
  546. for (j = 0; j < 3; j++)
  547. {
  548. path.clear();
  549. path.push_back(2 - j);
  550. for (k = 0; k < (int)MazePaths[i].size(); k++)
  551. {
  552. path.push_back(MazePaths[i][k]);
  553. }
  554. path.push_back(DoorAssociations[j]);
  555. path.push_back(WAIT);
  556. if (runTrial(0, j, path, false)) { fitness += 1.0; }
  557. }
  558. }
  559. }
  560. // Run a trial.
  561. bool runTrial(int x, int y, vector<int>& path, bool train)
  562. {
  563. int i, j, cx, cy, response;
  564. vector<Mona::SENSOR> sensors;
  565. bool hopped;
  566. // Set up sensors.
  567. sensors.resize(5);
  568. // Clear working memory.
  569. mouse->clearWorkingMemory();
  570. // Reset need.
  571. mouse->setNeed(0, CHEESE_NEED);
  572. // Place mouse.
  573. mouseX = x;
  574. mouseY = y;
  575. // Run maze path.
  576. hopped = false;
  577. for (i = 0; i < (int)path.size(); i++)
  578. {
  579. // Override response?
  580. if (train || (path[i] == WAIT))
  581. {
  582. mouse->responseOverride = path[i];
  583. }
  584. // Prepare sensors.
  585. for (j = 0; j < 3; j++)
  586. {
  587. if (maze[mouseX][mouseY]->doors[j] != NULL)
  588. {
  589. sensors[j] = 1.0;
  590. }
  591. else if (SeeAllMazeDoors &&
  592. (mouseX > beginMazeIndex) && (mouseX < endMazeIndex))
  593. {
  594. // Maze room door is visible although possibly blocked.
  595. sensors[j] = 1.0;
  596. }
  597. else
  598. {
  599. sensors[j] = 0.0;
  600. }
  601. }
  602. sensors[3] = (Mona::SENSOR)maze[mouseX][mouseY]->type;
  603. if (mouseX == endMazeIndex + 1)
  604. {
  605. sensors[4] = 1.0;
  606. }
  607. else
  608. {
  609. sensors[4] = 0.0;
  610. }
  611. // Initiate sensory/response cycle.
  612. response = mouse->cycle(sensors);
  613. // Clear override.
  614. mouse->responseOverride = Mona::NULL_RESPONSE;
  615. // Successful trial?
  616. if (path[i] == WAIT) { return(true); }
  617. // Hop at start of maze is OK.
  618. if ((mouseX == beginMazeIndex) && (response == HOP) &&
  619. (path[i] != HOP) && !hopped)
  620. {
  621. hopped = true;
  622. i--;
  623. continue;
  624. }
  625. // Wrong response ends trial unsuccessfully.
  626. if (response != path[i]) { return(false); }
  627. // Move mouse.
  628. if (response == HOP)
  629. {
  630. mouseX = endMazeIndex;
  631. mouseY = 0;
  632. }
  633. else
  634. {
  635. cx = (maze[mouseX][mouseY]->doors[response])->cx;
  636. cy = (maze[mouseX][mouseY]->doors[response])->cy;
  637. mouseX = cx;
  638. mouseY = cy;
  639. }
  640. }
  641. return(false);
  642. }
  643. // Get fitness.
  644. double getFitness()
  645. {
  646. return(fitness);
  647. }
  648. // Create mutated member by varying brain parameters.
  649. void mutate(Member *member)
  650. {
  651. brainParmMutator->copy(member->brainParmMutator);
  652. brainParmMutator->mutate();
  653. }
  654. // Merge given member brain parameters into this brain.
  655. void mindMeld(Member *member1, Member *member2)
  656. {
  657. brainParmMutator->meld(member1->brainParmMutator,
  658. member2->brainParmMutator);
  659. }
  660. // Load.
  661. void load(FILE *fp)
  662. {
  663. FREAD_INT(&id, fp);
  664. mouse->load(fp);
  665. FREAD_DOUBLE(&fitness, fp);
  666. FREAD_INT(&generation, fp);
  667. }
  668. // Save.
  669. void save(FILE *fp)
  670. {
  671. FWRITE_INT(&id, fp);
  672. mouse->save(fp);
  673. FWRITE_DOUBLE(&fitness, fp);
  674. FWRITE_INT(&generation, fp);
  675. }
  676. // Print.
  677. void print(FILE *out = stdout)
  678. {
  679. fprintf(out, "id=%d, fitness=%f, generation=%d\n",
  680. id, getFitness(), generation);
  681. fprintf(out, "mouse brain:\n");
  682. mouse->printParms(out);
  683. }
  684. };
  685. int Member::idDispenser = 0;
  686. // Population.
  687. Member *Population[POPULATION_SIZE];
  688. // Start/end functions.
  689. void logParameters();
  690. void print();
  691. void load();
  692. void save();
  693. void loadPopulation(FILE *fp);
  694. void savePopulation(FILE *fp);
  695. // Create maze-learning task.
  696. void createTask();
  697. // Evolve functions.
  698. void evolve(), evaluate(), prune(), mutate(), mate();
  699. #ifdef WIN32
  700. #ifdef _DEBUG
  701. // For Windows memory checking, set CHECK_MEMORY = 1.
  702. #define CHECK_MEMORY 0
  703. #if (CHECK_MEMORY == 1)
  704. #define MEMORY_CHECK_FILE "memory.txt"
  705. #include <crtdbg.h>
  706. #endif
  707. #endif
  708. #endif
  709. // Main.
  710. int main(int argc, char *argv[])
  711. {
  712. int i;
  713. #if (CHECK_MEMORY == 1)
  714. {
  715. #endif
  716. #ifdef WIN32
  717. // Attach to parent console?
  718. if (_isatty(1))
  719. {
  720. for (i = 1; i < argc; i++)
  721. {
  722. if (strcmp(argv[i], "-attachConsole") == 0)
  723. {
  724. break;
  725. }
  726. }
  727. if (i < argc)
  728. {
  729. FreeConsole();
  730. if (AttachConsole(ATTACH_PARENT_PROCESS))
  731. {
  732. freopen("CONOUT$", "w", stdout);
  733. freopen("CONOUT$", "w", stderr);
  734. freopen("CONIN$", "r", stdin);
  735. }
  736. }
  737. }
  738. #endif
  739. // Initialize logging..
  740. Log::LOGGING_FLAG = LOG_TO_PRINT;
  741. // Parse arguments.
  742. for (i = 1; i < argc; i++)
  743. {
  744. if (strcmp(argv[i], "-generations") == 0)
  745. {
  746. i++;
  747. if (i >= argc)
  748. {
  749. printUsage();
  750. exit(1);
  751. }
  752. Generations = atoi(argv[i]);
  753. if (Generations < 0)
  754. {
  755. printUsage();
  756. exit(1);
  757. }
  758. continue;
  759. }
  760. if (strcmp(argv[i], "-numMazeTests") == 0)
  761. {
  762. i++;
  763. if (i >= argc)
  764. {
  765. printUsage();
  766. exit(1);
  767. }
  768. NumMazeTests = atoi(argv[i]);
  769. if (NumMazeTests < 0)
  770. {
  771. printError((char *)"Invalid number of maze tests");
  772. printUsage();
  773. exit(1);
  774. }
  775. continue;
  776. }
  777. if (strcmp(argv[i], "-numDoorTrainingTrials") == 0)
  778. {
  779. i++;
  780. if (i >= argc)
  781. {
  782. printUsage();
  783. exit(1);
  784. }
  785. NumDoorTrainingTrials = atoi(argv[i]);
  786. if (NumDoorTrainingTrials < 0)
  787. {
  788. printError((char *)"Invalid number of door association training trials");
  789. printUsage();
  790. exit(1);
  791. }
  792. continue;
  793. }
  794. if (strcmp(argv[i], "-numMazeTrainingTrials") == 0)
  795. {
  796. i++;
  797. if (i >= argc)
  798. {
  799. printUsage();
  800. exit(1);
  801. }
  802. NumMazeTrainingTrials = atoi(argv[i]);
  803. if (NumMazeTrainingTrials < 0)
  804. {
  805. printError((char *)"Invalid number of maze association training trials");
  806. printUsage();
  807. exit(1);
  808. }
  809. continue;
  810. }
  811. if (strcmp(argv[i], "-mutationRate") == 0)
  812. {
  813. i++;
  814. if (i >= argc)
  815. {
  816. printUsage();
  817. exit(1);
  818. }
  819. MutationRate = atof(argv[i]);
  820. if (MutationRate < 0.0)
  821. {
  822. printUsage();
  823. exit(1);
  824. }
  825. continue;
  826. }
  827. if (strcmp(argv[i], "-randomSeed") == 0)
  828. {
  829. i++;
  830. if (i >= argc)
  831. {
  832. printUsage();
  833. exit(1);
  834. }
  835. RandomSeed = (RANDOM)atoi(argv[i]);
  836. continue;
  837. }
  838. if (strcmp(argv[i], "-print") == 0)
  839. {
  840. Print = true;
  841. continue;
  842. }
  843. if (strcmp(argv[i], "-input") == 0)
  844. {
  845. i++;
  846. if (i >= argc)
  847. {
  848. printUsage();
  849. exit(1);
  850. }
  851. InputFileName = argv[i];
  852. continue;
  853. }
  854. if (strcmp(argv[i], "-output") == 0)
  855. {
  856. i++;
  857. if (i >= argc)
  858. {
  859. printUsage();
  860. exit(1);
  861. }
  862. OutputFileName = argv[i];
  863. continue;
  864. }
  865. if (strcmp(argv[i], "-logfile") == 0)
  866. {
  867. i++;
  868. if (i >= argc)
  869. {
  870. printUsage();
  871. exit(1);
  872. }
  873. Log::LOGGING_FLAG = LOG_TO_FILE;
  874. Log::setLogFileName(argv[i]);
  875. continue;
  876. }
  877. if (strcmp(argv[i], "-ignoreInterrupts") == 0)
  878. {
  879. signal(SIGINT, SIG_IGN);
  880. continue;
  881. }
  882. #ifdef WIN32
  883. if (strcmp(argv[i], "-attachConsole") == 0)
  884. {
  885. continue;
  886. }
  887. #endif
  888. if (strcmp(argv[i], "-version") == 0)
  889. {
  890. printEvolveVersion();
  891. Mona::printVersion();
  892. exit(0);
  893. }
  894. printUsage();
  895. exit(1);
  896. }
  897. // Check operation combinations.
  898. if (Generations >= 0)
  899. {
  900. if (!Print && (OutputFileName == NULL))
  901. {
  902. printError((char *)"No print or file output");
  903. printUsage();
  904. exit(1);
  905. }
  906. }
  907. else
  908. {
  909. if (!Print)
  910. {
  911. printError((char *)"Must run or print");
  912. printUsage();
  913. exit(1);
  914. }
  915. }
  916. // Build the maze.
  917. buildMaze();
  918. // Initialize.
  919. if (InputFileName != NULL)
  920. {
  921. // Load population.
  922. if (RandomSeed != INVALID_RANDOM)
  923. {
  924. printError((char *)"Random seed is loaded from input file");
  925. printUsage();
  926. exit(1);
  927. }
  928. load();
  929. }
  930. else
  931. {
  932. if (RandomSeed == INVALID_RANDOM)
  933. {
  934. RandomSeed = (RANDOM)time(NULL);
  935. }
  936. Randomizer = new Random(RandomSeed);
  937. assert(Randomizer != NULL);
  938. Randomizer->SRAND(RandomSeed);
  939. // Create maze-learning task.
  940. createTask();
  941. // Create population.
  942. for (i = 0; i < POPULATION_SIZE; i++)
  943. {
  944. Population[i] = new Member(0);
  945. assert(Population[i] != NULL);
  946. }
  947. }
  948. // Log run parameters.
  949. if (Generations >= 0)
  950. {
  951. Log::logInformation((char *)"Initializing evolve:");
  952. if (Generations >= 0)
  953. {
  954. sprintf(Log::messageBuf, "generations=%d", Generations);
  955. Log::logInformation();
  956. }
  957. if (InputFileName != NULL)
  958. {
  959. sprintf(Log::messageBuf, "input=%s", InputFileName);
  960. Log::logInformation();
  961. }
  962. if (OutputFileName != NULL)
  963. {
  964. sprintf(Log::messageBuf, "output=%s", OutputFileName);
  965. Log::logInformation();
  966. }
  967. logParameters();
  968. // Evolution loop.
  969. Log::logInformation((char *)"Begin evolve:");
  970. for (i = 0; i < Generations; i++, Generation++)
  971. {
  972. sprintf(Log::messageBuf, "Generation=%d", Generation);
  973. Log::logInformation();
  974. evolve();
  975. // Save population?
  976. if (OutputFileName != NULL)
  977. {
  978. if ((i % SAVE_FREQUENCY) == 0)
  979. {
  980. save();
  981. }
  982. }
  983. }
  984. }
  985. // Save population.
  986. if (OutputFileName != NULL)
  987. {
  988. save();
  989. }
  990. // Print population.
  991. if (Print)
  992. {
  993. print();
  994. }
  995. // Release memory.
  996. for (i = 0; i < POPULATION_SIZE; i++)
  997. {
  998. if (Population[i] != NULL)
  999. {
  1000. delete Population[i];
  1001. Population[i] = NULL;
  1002. }
  1003. }
  1004. // Close log.
  1005. if (Generations >= 0)
  1006. {
  1007. Log::logInformation((char *)"End evolve");
  1008. }
  1009. Log::close();
  1010. #if (CHECK_MEMORY == 1)
  1011. }
  1012. // Check for memory leaks.
  1013. printf("Checking for memory leaks, report in file %s\n",
  1014. MEMORY_CHECK_FILE);
  1015. HANDLE hFile = CreateFile(
  1016. MEMORY_CHECK_FILE,
  1017. GENERIC_WRITE,
  1018. FILE_SHARE_WRITE,
  1019. NULL,
  1020. OPEN_ALWAYS,
  1021. 0,
  1022. NULL
  1023. );
  1024. if (hFile == INVALID_HANDLE_VALUE)
  1025. {
  1026. fprintf(stderr, "Cannot open memory check file %s",
  1027. MEMORY_CHECK_FILE);
  1028. exit(1);
  1029. }
  1030. _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
  1031. _CrtSetReportFile(_CRT_WARN, hFile);
  1032. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
  1033. _CrtSetReportFile(_CRT_ERROR, hFile);
  1034. if (!_CrtDumpMemoryLeaks())
  1035. {
  1036. printf("No memory leaks\n");
  1037. }
  1038. else
  1039. {
  1040. printf("Memory leaks found\n");
  1041. }
  1042. CloseHandle(hFile);
  1043. #endif
  1044. return(0);
  1045. }
  1046. // Log run parameters.
  1047. void logParameters()
  1048. {
  1049. Log::logInformation((char *)"Evolve Parameters:");
  1050. sprintf(Log::messageBuf, "FIT_POPULATION_SIZE = %d", FIT_POPULATION_SIZE);
  1051. Log::logInformation();
  1052. sprintf(Log::messageBuf, "NUM_MUTANTS = %d", NUM_MUTANTS);
  1053. Log::logInformation();
  1054. sprintf(Log::messageBuf, "NUM_OFFSPRING = %d", NUM_OFFSPRING);
  1055. Log::logInformation();
  1056. sprintf(Log::messageBuf, "NumMazeTests = %d", NumMazeTests);
  1057. Log::logInformation();
  1058. sprintf(Log::messageBuf, "NumDoorTrainingTrials = %d", NumDoorTrainingTrials);
  1059. Log::logInformation();
  1060. sprintf(Log::messageBuf, "NumMazeTrainingTrials = %d", NumMazeTrainingTrials);
  1061. Log::logInformation();
  1062. sprintf(Log::messageBuf, "MutationRate = %f", MutationRate);
  1063. Log::logInformation();
  1064. sprintf(Log::messageBuf, "RandomSeed = %lu", RandomSeed);
  1065. Log::logInformation();
  1066. sprintf(Log::messageBuf, "Door associations: 0->%d, 1->%d, 2->%d",
  1067. DoorAssociations[0], DoorAssociations[1], DoorAssociations[2]);
  1068. Log::logInformation();
  1069. Log::logInformation((char *)"Maze paths (doors):");
  1070. for (int i = 0; i < (int)MazePaths.size(); i++)
  1071. {
  1072. sprintf(Log::messageBuf, "%d %d %d %d",
  1073. MazePaths[i][0], MazePaths[i][1], MazePaths[i][2], MazePaths[i][3]);
  1074. Log::logInformation();
  1075. }
  1076. }
  1077. // Print population.
  1078. void print()
  1079. {
  1080. if ((Log::LOGGING_FLAG == LOG_TO_FILE) ||
  1081. (Log::LOGGING_FLAG == LOG_TO_BOTH))
  1082. {
  1083. if (Log::logfp != NULL)
  1084. {
  1085. for (int i = 0; i < POPULATION_SIZE; i++)
  1086. {
  1087. Population[i]->print(Log::logfp);
  1088. }
  1089. fflush(Log::logfp);
  1090. }
  1091. }
  1092. if ((Log::LOGGING_FLAG == LOG_TO_PRINT) ||
  1093. (Log::LOGGING_FLAG == LOG_TO_BOTH))
  1094. {
  1095. for (int i = 0; i < POPULATION_SIZE; i++)
  1096. {
  1097. Population[i]->print();
  1098. }
  1099. }
  1100. }
  1101. // Load evolve.
  1102. void load()
  1103. {
  1104. int i, j, k, n;
  1105. FILE *fp;
  1106. char buf[200];
  1107. assert(InputFileName != NULL);
  1108. if ((fp = FOPEN_READ(InputFileName)) == NULL)
  1109. {
  1110. sprintf(buf, "Cannot load population file %s", InputFileName);
  1111. printError(buf);
  1112. exit(1);
  1113. }
  1114. FREAD_INT(&Member::idDispenser, fp);
  1115. FREAD_LONG(&RandomSeed, fp);
  1116. Randomizer = new Random(RandomSeed);
  1117. assert(Randomizer != NULL);
  1118. Randomizer->RAND_LOAD(fp);
  1119. FREAD_INT(&Generation, fp);
  1120. for (i = 0; i < 3; i++)
  1121. {
  1122. FREAD_INT(&DoorAssociations[i], fp);
  1123. }
  1124. MazePaths.clear();
  1125. FREAD_INT(&i, fp);
  1126. MazePaths.resize(i);
  1127. for (j = 0; j < i; j++)
  1128. {
  1129. for (k = 0; k < 4; k++)
  1130. {
  1131. FREAD_INT(&n, fp);
  1132. MazePaths[j].push_back(n);
  1133. }
  1134. }
  1135. loadPopulation(fp);
  1136. FCLOSE(fp);
  1137. }
  1138. // Save evolve.
  1139. void save()
  1140. {
  1141. int i, j, k, n;
  1142. FILE *fp;
  1143. char buf[200];
  1144. assert(OutputFileName != NULL);
  1145. if ((fp = FOPEN_WRITE(OutputFileName)) == NULL)
  1146. {
  1147. sprintf(buf, "Cannot save to population file %s", OutputFileName);
  1148. printError(buf);
  1149. exit(1);
  1150. }
  1151. FWRITE_INT(&Member::idDispenser, fp);
  1152. FWRITE_LONG(&RandomSeed, fp);
  1153. Randomizer->RAND_SAVE(fp);
  1154. FWRITE_INT(&Generation, fp);
  1155. for (i = 0; i < 3; i++)
  1156. {
  1157. FWRITE_INT(&DoorAssociations[i], fp);
  1158. }
  1159. i = (int)MazePaths.size();
  1160. FWRITE_INT(&i, fp);
  1161. for (j = 0; j < i; j++)
  1162. {
  1163. for (k = 0; k < 4; k++)
  1164. {
  1165. n = MazePaths[j][k];
  1166. FWRITE_INT(&n, fp);
  1167. }
  1168. }
  1169. savePopulation(fp);
  1170. FCLOSE(fp);
  1171. }
  1172. // Load evolution population.
  1173. void loadPopulation(FILE *fp)
  1174. {
  1175. for (int i = 0; i < POPULATION_SIZE; i++)
  1176. {
  1177. Population[i] = new Member();
  1178. assert(Population[i] != NULL);
  1179. Population[i]->load(fp);
  1180. }
  1181. }
  1182. // Save evolution population.
  1183. void savePopulation(FILE *fp)
  1184. {
  1185. for (int i = 0; i < POPULATION_SIZE; i++)
  1186. {
  1187. Population[i]->save(fp);
  1188. }
  1189. }
  1190. // Create maze-learning task.
  1191. void createTask()
  1192. {
  1193. int i, j, k;
  1194. DoorAssociations[0] = Randomizer->RAND_CHOICE(3);
  1195. DoorAssociations[1] = DoorAssociations[0];
  1196. while (DoorAssociations[1] == DoorAssociations[0])
  1197. {
  1198. DoorAssociations[1] = Randomizer->RAND_CHOICE(3);
  1199. }
  1200. DoorAssociations[2] = DoorAssociations[0];
  1201. while (DoorAssociations[2] == DoorAssociations[0] ||
  1202. DoorAssociations[2] == DoorAssociations[1])
  1203. {
  1204. DoorAssociations[2] = Randomizer->RAND_CHOICE(3);
  1205. }
  1206. MazePaths.clear();
  1207. MazePaths.resize(NumMazeTests);
  1208. for (i = 0; i < NumMazeTests; i++)
  1209. {
  1210. while (true)
  1211. {
  1212. MazePaths[i].clear();
  1213. for (j = k = 0; j < 4; j++)
  1214. {
  1215. MazePaths[i].push_back(Randomizer->RAND_CHOICE(3));
  1216. k += (MazePaths[i][j] - 1);
  1217. }
  1218. if (k == 0)
  1219. {
  1220. break;
  1221. }
  1222. }
  1223. }
  1224. }
  1225. // Evolution generation.
  1226. void evolve()
  1227. {
  1228. // Evaluate member fitness.
  1229. evaluate();
  1230. // Prune unfit members.
  1231. prune();
  1232. // Create new members by mutation.
  1233. mutate();
  1234. // Create new members by mating.
  1235. mate();
  1236. }
  1237. // Evaluate member fitnesses.
  1238. void evaluate()
  1239. {
  1240. Log::logInformation((char *)"Evaluate:");
  1241. for (int i = 0; i < POPULATION_SIZE; i++)
  1242. {
  1243. Population[i]->evaluate();
  1244. sprintf(Log::messageBuf, " Member=%d, Mouse=%d, Fitness=%f, Generation=%d",
  1245. i, Population[i]->id, Population[i]->getFitness(),
  1246. Population[i]->generation);
  1247. Log::logInformation();
  1248. }
  1249. }
  1250. // Prune unfit members.
  1251. void prune()
  1252. {
  1253. double max;
  1254. int i, j, m;
  1255. Member *member;
  1256. Member *fitPopulation[FIT_POPULATION_SIZE];
  1257. Log::logInformation((char *)"Select:");
  1258. for (i = 0; i < FIT_POPULATION_SIZE; i++)
  1259. {
  1260. m = -1;
  1261. for (j = 0; j < POPULATION_SIZE; j++)
  1262. {
  1263. member = Population[j];
  1264. if (member == NULL)
  1265. {
  1266. continue;
  1267. }
  1268. if ((m == -1) || (member->getFitness() > max))
  1269. {
  1270. m = j;
  1271. max = member->getFitness();
  1272. }
  1273. }
  1274. member = Population[m];
  1275. Population[m] = NULL;
  1276. fitPopulation[i] = member;
  1277. sprintf(Log::messageBuf, " Mouse=%d, Fitness=%f, Generation=%d",
  1278. member->id, member->getFitness(), member->generation);
  1279. Log::logInformation();
  1280. }
  1281. for (i = 0; i < POPULATION_SIZE; i++)
  1282. {
  1283. if (Population[i] != NULL)
  1284. {
  1285. delete Population[i];
  1286. Population[i] = NULL;
  1287. }
  1288. }
  1289. for (i = 0; i < FIT_POPULATION_SIZE; i++)
  1290. {
  1291. Population[i] = fitPopulation[i];
  1292. }
  1293. }
  1294. // Mutate members.
  1295. void mutate()
  1296. {
  1297. int i, j;
  1298. Member *member, *mutant;
  1299. Log::logInformation((char *)"Mutate:");
  1300. for (i = 0; i < NUM_MUTANTS; i++)
  1301. {
  1302. // Select a fit member to mutate.
  1303. j = Randomizer->RAND_CHOICE(FIT_POPULATION_SIZE);
  1304. member = Population[j];
  1305. // Create mutant member.
  1306. mutant = new Member(member->generation + 1);
  1307. assert(mutant != NULL);
  1308. Population[FIT_POPULATION_SIZE + i] = mutant;
  1309. sprintf(Log::messageBuf, " Member=%d, Mouse=%d -> Member=%d, Mouse=%d",
  1310. j, member->id, FIT_POPULATION_SIZE + i,
  1311. mutant->id);
  1312. Log::logInformation();
  1313. // Mutate.
  1314. mutant->mutate(member);
  1315. }
  1316. }
  1317. // Produce offspring by "mind melding" parent brain parameters.
  1318. void mate()
  1319. {
  1320. int i, j, k;
  1321. Member *member1, *member2, *offspring;
  1322. Log::logInformation((char *)"Mate:");
  1323. if (FIT_POPULATION_SIZE < 2)
  1324. {
  1325. return;
  1326. }
  1327. for (i = 0; i < NUM_OFFSPRING; i++)
  1328. {
  1329. // Select a pair of fit members to mate.
  1330. j = Randomizer->RAND_CHOICE(FIT_POPULATION_SIZE);
  1331. member1 = Population[j];
  1332. while ((k = Randomizer->RAND_CHOICE(FIT_POPULATION_SIZE)) == j)
  1333. {
  1334. }
  1335. member2 = Population[k];
  1336. // Create offspring.
  1337. offspring = new Member((member1->generation > member2->generation ?
  1338. member1->generation : member2->generation) + 1);
  1339. assert(offspring != NULL);
  1340. Population[FIT_POPULATION_SIZE + NUM_MUTANTS + i] = offspring;
  1341. sprintf(Log::messageBuf, " Members=%d,%d, Mice=%d,%d -> Member=%d, Mouse=%d",
  1342. j, k, member1->id, member2->id,
  1343. FIT_POPULATION_SIZE + NUM_MUTANTS + i, offspring->id);
  1344. Log::logInformation();
  1345. // Combine parent brains into offspring.
  1346. offspring->mindMeld(member1, member2);
  1347. }
  1348. }