文本文件中的微型 GP 输出

Tiny GP output in text file

我最近偶然发现了 Tiny GP(一个遗传编程程序),我发现它非常有用,所以我决定将程序中的所有 System.out.println() 更改为写入文本文件的方法。

问题:在文本文件中,出于某种原因,只说 "PROBLEM SOLVED",而不是打印出世代和其他它应该打印的东西(见代码)。

Tiny GP 已修改 class 文件:

package main;

/*
 * Program:   tiny_gp.java
 *
 * Author:    Riccardo Poli (email: rpoli@essex.ac.uk)
 *
 * Modified by Preston Tang 
 */
import java.util.*;
import java.io.*;
import java.text.DecimalFormat;

public class tiny_gp {

    String Name;
    double[] fitness;
    char[][] pop;
    static Random rd = new Random();
    static final int ADD = 110,
            SUB = 111,
            MUL = 112,
            DIV = 113,
            FSET_START = ADD,
            FSET_END = DIV;
    static double[] x = new double[FSET_START];
    static double minrandom, maxrandom;
    static char[] program;
    static int PC;
    static int varnumber, fitnesscases, randomnumber;
    static double fbestpop = 0.0, favgpop = 0.0;
    static long seed;
    static double avg_len;
    static final int MAX_LEN = 10000,
            POPSIZE = 100000,
            DEPTH = 5,
            GENERATIONS = 100,
            TSIZE = 2;
    public static final double PMUT_PER_NODE = 0.05,
            CROSSOVER_PROB = 0.9;
    public static double[][] targets;

    public double run() {
        /* Interpreter */

        char primitive = program[PC++];
        if (primitive < FSET_START) {
            return (x[primitive]);
        }
        switch (primitive) {
            case ADD:
                return (run() + run());
            case SUB:
                return (run() - run());
            case MUL:
                return (run() * run());
            case DIV: {
                double num = run(), den = run();
                if (Math.abs(den) <= 0.001) {
                    return (num);
                } else {
                    return (num / den);
                }
            }
        }
        return (0.0); // should never get here
    }

    public int traverse(char[] buffer, int buffercount) {
        if (buffer[buffercount] < FSET_START) {
            return (++buffercount);
        }

        switch (buffer[buffercount]) {
            case ADD:
            case SUB:
            case MUL:
            case DIV:
                return (traverse(buffer, traverse(buffer, ++buffercount)));
        }
        return (0); // should never get here
    }

    public void setup_fitness(String fname) {
        try {
            int i, j;
            String line;

            BufferedReader in
                    = new BufferedReader(
                            new FileReader(fname));
            line = in.readLine();
            StringTokenizer tokens = new StringTokenizer(line);
            varnumber = Integer.parseInt(tokens.nextToken().trim());
            randomnumber = Integer.parseInt(tokens.nextToken().trim());
            minrandom = Double.parseDouble(tokens.nextToken().trim());
            maxrandom = Double.parseDouble(tokens.nextToken().trim());
            fitnesscases = Integer.parseInt(tokens.nextToken().trim());
            targets = new double[fitnesscases][varnumber + 1];
            if (varnumber + randomnumber >= FSET_START) {
                Write("too many variables and constants");
                //System.out.println("too many variables and constants");
            }

            for (i = 0; i < fitnesscases; i++) {
                line = in.readLine();
                tokens = new StringTokenizer(line);
                for (j = 0; j <= varnumber; j++) {
                    targets[i][j] = Double.parseDouble(tokens.nextToken().trim());
                }
            }
            in.close();
        } catch (FileNotFoundException e) {
            Write("ERROR: Please provide a data file");
//System.out.println("ERROR: Please provide a data file");
            System.exit(0);
        } catch (Exception e) {
            Write("ERROR: Incorrect data format");
            //System.out.println("ERROR: Incorrect data format");
            System.exit(0);
        }
    }

    public double fitness_function(char[] Prog) {
        int i = 0, len;
        double result, fit = 0.0;

        len = traverse(Prog, 0);
        for (i = 0; i < fitnesscases; i++) {
            for (int j = 0; j < varnumber; j++) {
                x[j] = targets[i][j];
            }
            program = Prog;
            PC = 0;
            result = run();
            fit += Math.abs(result - targets[i][varnumber]);
        }
        return (-fit);
    }

    public int grow(char[] buffer, int pos, int max, int depth) {
        char prim = (char) rd.nextInt(2);
        int one_child;

        if (pos >= max) {
            return (-1);
        }

        if (pos == 0) {
            prim = 1;
        }

        if (prim == 0 || depth == 0) {
            prim = (char) rd.nextInt(varnumber + randomnumber);
            buffer[pos] = prim;
            return (pos + 1);
        } else {
            prim = (char) (rd.nextInt(FSET_END - FSET_START + 1) + FSET_START);
            switch (prim) {
                case ADD:
                case SUB:
                case MUL:
                case DIV:
                    buffer[pos] = prim;
                    one_child = grow(buffer, pos + 1, max, depth - 1);
                    if (one_child < 0) {
                        return (-1);
                    }
                    return (grow(buffer, one_child, max, depth - 1));
            }
        }
        return (0); // should never get here
    }

    public int print_indiv(char[] buffer, int buffercounter) {
        int a1 = 0, a2;
        if (buffer[buffercounter] < FSET_START) {
            if (buffer[buffercounter] < varnumber) {
                Write("X" + (buffer[buffercounter] + 1) + " ");
                //System.out.print("X" + (buffer[buffercounter] + 1) + " ");
            } else {
                WriteDouble(x[buffer[buffercounter]]);
                //System.out.print(x[buffer[buffercounter]]);
            }
            return (++buffercounter);
        }
        switch (buffer[buffercounter]) {
            case ADD:
                Write("(");
                //System.out.print("(");
                a1 = print_indiv(buffer, ++buffercounter);
                Write(" + ");
                //System.out.print(" + ");
                break;
            case SUB:
                Write("(");
                //System.out.print("(");
                a1 = print_indiv(buffer, ++buffercounter);
                Write(" - ");
                //System.out.print(" - ");
                break;
            case MUL:
                Write("(");
                //System.out.print("(");
                a1 = print_indiv(buffer, ++buffercounter);
                Write(" * ");
                //System.out.print(" * ");
                break;
            case DIV:
                Write("(");
                //System.out.print("(");
                a1 = print_indiv(buffer, ++buffercounter);
                Write(" / ");
                //System.out.print(" / ");
                break;
        }
        a2 = print_indiv(buffer, a1);
        Write(")");
        //System.out.print(")");
        return (a2);
    }

    public static char[] buffer = new char[MAX_LEN];

    public char[] create_random_indiv(int depth) {
        char[] ind;
        int len;

        len = grow(buffer, 0, MAX_LEN, depth);

        while (len < 0) {
            len = grow(buffer, 0, MAX_LEN, depth);
        }

        ind = new char[len];

        System.arraycopy(buffer, 0, ind, 0, len);
        return (ind);
    }

    public char[][] create_random_pop(int n, int depth, double[] fitness) {
        char[][] pop = new char[n][];
        int i;

        for (i = 0; i < n; i++) {
            pop[i] = create_random_indiv(depth);
            fitness[i] = fitness_function(pop[i]);
        }
        return (pop);
    }

    public void stats(double[] fitness, char[][] pop, int gen) {
        int i, best = rd.nextInt(POPSIZE);
        int node_count = 0;
        fbestpop = fitness[best];
        favgpop = 0.0;

        for (i = 0; i < POPSIZE; i++) {
            node_count += traverse(pop[i], 0);
            favgpop += fitness[i];
            if (fitness[i] > fbestpop) {
                best = i;
                fbestpop = fitness[i];
            }
        }
        avg_len = (double) node_count / POPSIZE;
        favgpop /= POPSIZE;
        Write("Generation=" + gen + " Avg Fitness=" + (-favgpop)
                + " Best Fitness=" + (-fbestpop) + " Avg Size=" + avg_len
                + "\nBest Individual: ");
        //System.out.print("Generation=" + gen + " Avg Fitness=" + (-favgpop)
        //        + " Best Fitness=" + (-fbestpop) + " Avg Size=" + avg_len
        //        + "\nBest Individual: ");
        print_indiv(pop[best], 0);
        Write("\n");
        //System.out.print("\n");
        //System.out.flush();
    }

    public int tournament(double[] fitness, int tsize) {
        int best = rd.nextInt(POPSIZE), i, competitor;
        double fbest = -1.0e34;

        for (i = 0; i < tsize; i++) {
            competitor = rd.nextInt(POPSIZE);
            if (fitness[competitor] > fbest) {
                fbest = fitness[competitor];
                best = competitor;
            }
        }
        return (best);
    }

    public int negative_tournament(double[] fitness, int tsize) {
        int worst = rd.nextInt(POPSIZE), i, competitor;
        double fworst = 1e34;

        for (i = 0; i < tsize; i++) {
            competitor = rd.nextInt(POPSIZE);
            if (fitness[competitor] < fworst) {
                fworst = fitness[competitor];
                worst = competitor;
            }
        }
        return (worst);
    }

    public char[] crossover(char[] parent1, char[] parent2) {
        int xo1start, xo1end, xo2start, xo2end;
        char[] offspring;
        int len1 = traverse(parent1, 0);
        int len2 = traverse(parent2, 0);
        int lenoff;

        xo1start = rd.nextInt(len1);
        xo1end = traverse(parent1, xo1start);

        xo2start = rd.nextInt(len2);
        xo2end = traverse(parent2, xo2start);

        lenoff = xo1start + (xo2end - xo2start) + (len1 - xo1end);

        offspring = new char[lenoff];

        System.arraycopy(parent1, 0, offspring, 0, xo1start);
        System.arraycopy(parent2, xo2start, offspring, xo1start,
                (xo2end - xo2start));
        System.arraycopy(parent1, xo1end, offspring,
                xo1start + (xo2end - xo2start),
                (len1 - xo1end));

        return (offspring);
    }

    public char[] mutation(char[] parent, double pmut) {
        int len = traverse(parent, 0), i;
        int mutsite;
        char[] parentcopy = new char[len];

        System.arraycopy(parent, 0, parentcopy, 0, len);
        for (i = 0; i < len; i++) {
            if (rd.nextDouble() < pmut) {
                mutsite = i;
                if (parentcopy[mutsite] < FSET_START) {
                    parentcopy[mutsite] = (char) rd.nextInt(varnumber + randomnumber);
                } else {
                    switch (parentcopy[mutsite]) {
                        case ADD:
                        case SUB:
                        case MUL:
                        case DIV:
                            parentcopy[mutsite]
                                    = (char) (rd.nextInt(FSET_END - FSET_START + 1)
                                    + FSET_START);
                    }
                }
            }
        }
        return (parentcopy);
    }

    public void print_parms() {
        Write("-- TINY GP (Java version) --\n");
        //System.out.print("-- TINY GP (Java version) --\n");
        Write("SEED=" + seed + "\nMAX_LEN=" + MAX_LEN
                + "\nPOPSIZE=" + POPSIZE + "\nDEPTH=" + DEPTH
                + "\nCROSSOVER_PROB=" + CROSSOVER_PROB
                + "\nPMUT_PER_NODE=" + PMUT_PER_NODE
                + "\nMIN_RANDOM=" + minrandom
                + "\nMAX_RANDOM=" + maxrandom
                + "\nGENERATIONS=" + GENERATIONS
                + "\nTSIZE=" + TSIZE
                + "\n----------------------------------\n");
//        System.out.print("SEED=" + seed + "\nMAX_LEN=" + MAX_LEN
//                + "\nPOPSIZE=" + POPSIZE + "\nDEPTH=" + DEPTH
//                + "\nCROSSOVER_PROB=" + CROSSOVER_PROB
//                + "\nPMUT_PER_NODE=" + PMUT_PER_NODE
//                + "\nMIN_RANDOM=" + minrandom
//                + "\nMAX_RANDOM=" + maxrandom
//                + "\nGENERATIONS=" + GENERATIONS
//                + "\nTSIZE=" + TSIZE
//                + "\n----------------------------------\n");
    }

    public tiny_gp(String fname, long s) {
        fitness = new double[POPSIZE];
        seed = s;
        if (seed >= 0) {
            rd.setSeed(seed);
        }
        setup_fitness(fname);
        for (int i = 0; i < FSET_START; i++) {
            x[i] = (maxrandom - minrandom) * rd.nextDouble() + minrandom;
        }
        pop = create_random_pop(POPSIZE, DEPTH, fitness);
    }

    public void evolve() {
        int gen = 0, indivs, offspring, parent1, parent2, parent;
        double newfit;
        char[] newind;
        print_parms();
        stats(fitness, pop, 0);
        for (gen = 1; gen < GENERATIONS; gen++) {
            if (fbestpop > -1e-5) {
                Write("PROBLEM SOLVED\n");
                //System.out.print("PROBLEM SOLVED\n");
                System.exit(0);
            }
            for (indivs = 0; indivs < POPSIZE; indivs++) {
                if (rd.nextDouble() < CROSSOVER_PROB) {
                    parent1 = tournament(fitness, TSIZE);
                    parent2 = tournament(fitness, TSIZE);
                    newind = crossover(pop[parent1], pop[parent2]);
                } else {
                    parent = tournament(fitness, TSIZE);
                    newind = mutation(pop[parent], PMUT_PER_NODE);
                }
                newfit = fitness_function(newind);
                offspring = negative_tournament(fitness, TSIZE);
                pop[offspring] = newind;
                fitness[offspring] = newfit;
            }
            stats(fitness, pop, gen);
        }
        Write("PROBLEM *NOT* SOLVED\n");
        //System.out.print("PROBLEM *NOT* SOLVED\n");
        System.exit(1);
    }

    public void Write(String context) {

        FileWriter fileWriter;
        try {
            fileWriter = new FileWriter("GP.txt");
            try (BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
                bufferedWriter.write(context);
            }

        } catch (IOException ex) {

        }
    }

    public void WriteDouble(double context) {

        FileWriter fileWriter;
        try {
            fileWriter = new FileWriter("GP.txt");
            try (BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
                String ncontext = Double.toString(context);
                bufferedWriter.write(ncontext);
            }

        } catch (IOException ex) {

        }
    }
};

使用 Tiny GP class 文件的 Functions Mapper 文件:

package function_mapper;

import javax.swing.JOptionPane;
import main.*;

public class Function_Mapper {

    public static void main(String[] args) {
        String fname = JOptionPane.showInputDialog(null, "File Name", "Input Dialog", JOptionPane.INFORMATION_MESSAGE);
        long s = -1;

        if (args.length == 2) {
            s = Integer.valueOf(args[0]).intValue();
            fname = args[1];
        }
        if (args.length == 1) {
            fname = args[0];
        }

        tiny_gp gp = new tiny_gp(fname, s);
        gp.evolve();
    }

}

非常感谢帮助,谢谢!

Write 方法在每次调用时覆盖文件的内容。有两种方法可以解决这个问题。

一个更简单的方法是追加文件,而不是覆盖它。可以通过将 append 参数传递给 FileWriter 来实现(我在此过程中稍微简化了代码)。

// true on the next line means "append"
try (Writer writer = new FileWriter("GP.txt", true)) { 
    writer.write(Double.toString(context));
} catch (IOException ex) {
}

一个更难但效率更高的方法是在构造函数中打开writer,在Write方法中使用它,并在[的特别引入的close方法中关闭tiny_gp.