summaryrefslogtreecommitdiff
path: root/src/genetic/ParallelChessGeneticProcess.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/genetic/ParallelChessGeneticProcess.java')
-rw-r--r--src/genetic/ParallelChessGeneticProcess.java267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/genetic/ParallelChessGeneticProcess.java b/src/genetic/ParallelChessGeneticProcess.java
new file mode 100644
index 0000000..75d9425
--- /dev/null
+++ b/src/genetic/ParallelChessGeneticProcess.java
@@ -0,0 +1,267 @@
+/*
+ Copyright 2007 Scott Gasch
+
+ Licensed under the Apache License, Version 2.0 (the "License"); you
+ may not use this file except in compliance with the License. You may
+ obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+*/
+
+package org.guru.wannabe.genetic;
+
+import java.io.*;
+import java.util.regex.*;
+
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class ParallelChessGeneticProcess implements GeneticProcess {
+ private static final int numProcessors = 4;
+ private static final String baselineDna = "./baseline.dna";
+ private static final String baselineLog = "./baseline.log";
+ private static final String scriptName = "./trial.ep_";
+
+ private int numGenerations;
+ private int numPerGeneration;
+ private int numSeeds;
+
+ // Helper function to emulate system(3).
+ private static void system(String cmd[]) {
+ Runtime runtime = Runtime.getRuntime();
+ try {
+ Process ps = runtime.exec(cmd);
+ InputStream stdin = ps.getInputStream();
+ InputStreamReader isr = new InputStreamReader(stdin);
+ BufferedReader br = new BufferedReader(isr);
+ String line = null;
+ while((line = br.readLine()) != null) ;
+ ps.waitFor();
+ } catch(Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ // Private helpers to build filenames
+ private static String seedFilename(int generation, int which) {
+ return "./gen" + generation + "_seed" + which + ".dna";
+ }
+
+ private static String logFilename(int generation, int which) {
+ return "./gen" + generation + "_" + which + ".log";
+ }
+
+ private static String dnaFilename(int generation, int which) {
+ return "./gen" + generation + "_" + which + ".dna";
+ }
+
+ // Uses mutate.pl to cause dna mutations
+ private static void mutate(String from, String to) {
+ String cmd[] = new String[] { "./mutate.pl", from, to };
+ system(cmd);
+ try {
+ BufferedWriter out =
+ new BufferedWriter(new FileWriter(to, true));
+ out.write("# mutate " + from + " -> " + to + "\n");
+ out.close();
+ } catch(IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ // Runs a chess trial event
+ private static void chessTrial(String dnaFile, String logFile) {
+ String cmd[] = new String[] { "./typhoon",
+ "--cpus", "1",
+ "--hash", "128m",
+ "--batch",
+ "--logfile", logFile,
+ "--dnafile", dnaFile,
+ "--command", "script ./trial.ep_" };
+ system(cmd);
+ }
+
+ // The mainInitialize method produces the 0th generation DNA from
+ // a seed file called "baseline.dna" using a helper script called
+ // mutate.pl (the generic DNA mutation routine).
+ public boolean mainInitialize(int numGenerations,
+ int numPerGeneration) {
+
+ System.out.println("Performing pre-generation setup tasks.");
+ this.numGenerations = numGenerations;
+ this.numPerGeneration = numPerGeneration;
+ this.numSeeds = numPerGeneration / 5;
+ if ((numGenerations <= 0) ||
+ (numPerGeneration <= 0) ||
+ (numSeeds <= 0)) {
+ throw new IllegalArgumentException("Bad value");
+ }
+
+ // Create generation zero seeds based on mutations of baseline.dna
+ for (int x = 0; x < numSeeds; x++) {
+ String seedFile = seedFilename(0, x);
+ if (!new File(seedFile).exists()) {
+ mutate(baselineDna, seedFile);
+ } else {
+ System.out.println("Using existing " + seedFile);
+ }
+ }
+
+ // Run baseline.dna trial to get a starting point.
+ if (!new File(baselineLog).exists()) {
+ chessTrial(baselineDna, baselineLog);
+ } else {
+ System.out.println("Using existing " + baselineLog);
+ }
+ return true;
+ }
+
+ public boolean generationInitialize(int generationNumber) {
+
+ // Using the seed dna of the previous generation, build the
+ // genes for the current generation.
+ System.out.println("Initializing generation " + generationNumber);
+ for (int x = 0; x < numPerGeneration; x++) {
+ String dnaFile = dnaFilename(generationNumber, x);
+ String seedFile = seedFilename(generationNumber, x % numSeeds);
+ mutate(seedFile, dnaFile);
+ }
+ return true;
+ }
+
+ public boolean generationEvaluation(int generationNumber) {
+ class ChessGame implements Runnable {
+ public String dnaFile;
+ public String logFile;
+ public ChessGame(String dnaFile, String logFile) {
+ this.dnaFile = dnaFile; this.logFile = logFile;
+ }
+ public void run() {
+ if (!new File(logFile).exists()) {
+ System.out.println("Creating " + logFile);
+ chessTrial(dnaFile, logFile);
+ } else {
+ System.out.println("Using existing " + logFile);
+ }
+ }
+ }
+
+ // Populate work queue
+ System.out.println("Evaluating generation " + generationNumber);
+ List<ChessGame> workQueue = new ArrayList<ChessGame>();
+ for (int x = 0; x < numPerGeneration; x++) {
+ String dnaFile = dnaFilename(generationNumber, x);
+ String logFile = logFilename(generationNumber, x);
+ workQueue.add(new ChessGame(dnaFile, logFile));
+ }
+
+ // Depopulate the work queue in parallel
+ Thread threadPool[] = new Thread[numProcessors];
+ while(!workQueue.isEmpty()) {
+ ChessGame next = workQueue.remove(0);
+ int x = 0;
+ do {
+ if ((threadPool[x] == null) ||
+ (!threadPool[x].isAlive())) {
+ threadPool[x] = new Thread(next);
+ threadPool[x].setPriority(Thread.MAX_PRIORITY);
+ threadPool[x].start();
+ break;
+ }
+ x++;
+ if (x >= numProcessors) {
+ x = 0;
+ try {
+ Thread.sleep(2000);
+ } catch(Exception e) {
+ ;
+ }
+ }
+ }
+ while(true);
+ }
+
+ // Wait for all threads to become idle again
+ int x = 0;
+ do {
+ if (threadPool[x] != null && threadPool[x].isAlive()) {
+ x = 0;
+ }
+ x++;
+ try {
+ Thread.sleep(2000);
+ } catch(Exception e) {
+ ;
+ }
+ } while(x < numProcessors);
+ return true;
+ }
+
+ public boolean generationReproduction(int generationNumber) {
+
+ // Helper data class
+ class FileAndScore implements Comparable<FileAndScore> {
+ public final String file;
+ public final int score;
+ public final int number;
+ public FileAndScore(String file, int score, int number) {
+ this.file = file; this.score = score; this.number = number;
+ }
+ public int compareTo(FileAndScore other) {
+ return other.score - score;
+ }
+ }
+
+ System.out.println("Seeding subsequent generation.");
+ List<FileAndScore> scores = new ArrayList<FileAndScore>();
+ for (int x = 0; x < numPerGeneration; x++) {
+ String logFile = logFilename(generationNumber, x);
+ try {
+ BufferedReader log = new BufferedReader(
+ new FileReader(logFile));
+ String line = null;
+ Pattern p =
+ Pattern.compile("\\s+correct solutions\\s+:\\s+(\\d+)");
+ while ((line = log.readLine()) != null) {
+ Matcher m = p.matcher(line);
+ if (m.matches()) {
+ int score = Integer.parseInt(m.group(1));
+ FileAndScore fas =
+ new FileAndScore(logFile, score, x);
+ scores.add(fas);
+ break;
+ }
+ }
+ log.close();
+ }
+ catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+ java.util.Collections.sort(scores);
+ for (int x = 0; x < numSeeds; x++) {
+ FileAndScore breeder = scores.get(0);
+ scores.remove(0);
+ String dnaFile = dnaFilename(generationNumber, breeder.number);
+ String seedFile = seedFilename(generationNumber + 1, x);
+ if (!new File(seedFile).exists()) {
+ System.out.println("Number " + breeder.number + " got score " +
+ breeder.score + " and will propagate.");
+ String cmd[] = new String[] { "/bin/cp", "-f", dnaFile, seedFile };
+ system(cmd);
+ } else {
+ System.out.println("Using existing " + seedFile);
+ }
+ }
+ return true;
+ }
+}