Skip to content
Snippets Groups Projects
SimpleRandomHillClimber.java 3.04 KiB
Newer Older
package ea;

import java.util.Arrays;
import java.util.Random;

public class SimpleRandomHillClimber {

    // Random mutation hill climber
    // using a relative (hence co-evolutionary)
    // fitness function
    static Random random = new Random();

    double[] bestYet;
    Eval2 eval;

    double stepFac = 0.1;

    // set stepAdjust to 1.0 to keep the stepFac fixed

    // on quadratic bowl 1.01 works much better than 1.0
    // which increases the step size every time a mutation
    // is successful and decreases it every time it fails
    // to improve
    // but be careful: could it make things worse in some cases?
    double stepAdjust = 1.01;

    // example ready for a minimal version of
    // co-evolution

    public static void main(String[] args) {
        int nEvals = 1000;
        int nDim = 10;
        double[] init = randVec(nDim);
        SimpleRandomHillClimber evo = new SimpleRandomHillClimber(init, new QuadraticBowl());

        evo.run(nEvals);

        System.out.println("Best Found: " + Arrays.toString(evo.bestYet));
        System.out.println("Fitness: " + mag2(evo.bestYet));

    }

    public SimpleRandomHillClimber(double[] bestYet, Eval2 eval) {
        this.bestYet = bestYet;
        this.eval = eval;
    }

    public void run(int nEvals) {
        for (int i=0; i<nEvals; i++) {
            // randomly mutate the best yet
            double[] mut = randMut(bestYet, stepFac);
            double diff = eval.pointsDiff(bestYet, mut);

            // if it's better then adopt the mutation as the new best
            if (diff >= 0) {
                bestYet = mut;
                // try making it bigger - make even faster progress
            } else {
                // try making the step size smaller
                stepFac /= stepAdjust;
            }
            System.out.println(i + "\t " + mag2(bestYet));
        }
    }

    // to evolve a game playing agent inject a and b into
    // game agent controllers and return the points difference
    // ensure to interpret the sign correctly
    // the example is set up to MINIMIZE a fitness score

    static interface Eval2 {
        double pointsDiff(double[] a, double[] b);
    }

    static double[] randVec(int n) {
        double[] x = new double[n];
        for (int i=0; i<n; i++) {
            x[i] = random.nextGaussian();
        }
        return x;
    }

    static double[] randMut(double[] v, double stepFac) {
        int n = v.length;
        double[] x = new double[n];
        for (int i=0; i<n; i++) {
            x[i] = v[i] + stepFac * random.nextGaussian();
        }
        return x;
    }

    static class QuadraticBowl implements Eval2 {

        @Override
        public double pointsDiff(double[] a, double[] b) {
            // simple example that evaluates quality as being
            // the minimum squared magnitude of a vector
            return mag2(a) - mag2(b);
        }
    }

    static double mag2(double[] v) {
        // square of the magnitude of the vector
        double tot = 0;
        for (double x : v) tot += x * x;
        return tot;
    }
}