Skip to content

Instantly share code, notes, and snippets.

@NeatMonster
Last active October 21, 2015 20:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NeatMonster/ab32ad4f1ea62a62ac32 to your computer and use it in GitHub Desktop.
Save NeatMonster/ab32ad4f1ea62a62ac32 to your computer and use it in GitHub Desktop.
Simple demo of a Genetic Algorithm (GA) (w/ JFreeChart)
package fr.neatmonster.labs;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public class GASimple extends JFrame {
private static final long serialVersionUID = 1L;
public static void main(final String[] args) {
try {
new GASimple("chrome.png");
} catch (final IOException e) {
e.printStackTrace();
}
}
private static final int POP_SIZE = 50;
private static final int GEN_SIZE = 125;
private static final float SEL_CUTOFF = 0.15f;
private static final float MUT_CHANCE = 0.01f;
private static final float MUT_AMOUNT = 0.10f;
private static final Random rnd = new Random();
private static int nextUniqueId = 0;
private class Individual implements Comparable<Individual> {
private final int uniqueId = ++nextUniqueId;
private final float[][] genome = new float[GEN_SIZE][7];
private final float fitness;
private final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
public Individual() {
for (int i = 0; i < GEN_SIZE; ++i)
for (int j = 0; j < 7; ++j)
genome[i][j] = rnd.nextFloat();
fitness = calcFitness();
}
public Individual(final Individual a, final Individual b) {
for (int i = 0; i < GEN_SIZE; ++i) {
final float[] src = rnd.nextBoolean() ? a.genome[i] : b.genome[i];
System.arraycopy(src, 0, genome[i], 0, 7);
for (int j = 0; j < 7; ++j)
if (rnd.nextFloat() < MUT_CHANCE) {
genome[i][j] += rnd.nextFloat() * 2f * MUT_AMOUNT - MUT_AMOUNT;
genome[i][j] = Math.max(0f, Math.min(1f, genome[i][j]));
}
}
fitness = calcFitness();
}
private float calcFitness() {
final Graphics g = image.getGraphics();
for (final float[] gene : genome) {
g.setColor(new Color(gene[0], gene[1], gene[2], gene[3]));
final int r = (int) (gene[6] * Math.max(width, height));
final int x = (int) (gene[4] * width);
final int y = (int) (gene[5] * height);
g.fillOval(x + r / 2, y + r / 2, r, r);
}
g.dispose();
float fitness = 0f;
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x) {
final Color c1 = new Color(image.getRGB(x, y));
final Color c2 = new Color(model.getRGB(x, y));
final int dA = c1.getAlpha() - c2.getAlpha();
final int dR = c1.getRed() - c2.getRed();
final int dG = c1.getGreen() - c2.getGreen();
final int dB = c1.getBlue() - c2.getBlue();
fitness += dA * dA + dR * dR + dG * dG + dB * dB;
}
return 1f - fitness / (width * height * 4f * 255f * 255f);
}
@Override
public int compareTo(final Individual other) {
final float cmp = other.fitness - fitness;
if (cmp == 0f)
return uniqueId - other.uniqueId;
return cmp > 0 ? 1 : -1;
}
}
private final BufferedImage model;
private final int width, height;
private int generation = 1;
private final List<Individual> population = new ArrayList<Individual>();
public GASimple(final String filename) throws IOException {
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
model = ImageIO.read(new File(filename));
width = model.getWidth();
height = model.getHeight();
setLayout(new GridLayout(1, 2));
final BufferedImage display = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
add(new JLabel(new ImageIcon(display)));
final XYSeries serie = new XYSeries("fitness");
add(new ChartPanel(ChartFactory.createXYLineChart("Fitness", "X", "Y",
new XYSeriesCollection(serie), PlotOrientation.VERTICAL, false, false, false)));
pack();
setVisible(true);
for (int i = 0; i < POP_SIZE; ++i)
population.add(new Individual());
final int selectCount = (int) Math.floor(POP_SIZE * SEL_CUTOFF);
while (true) {
Collections.sort(population);
final Individual best = population.get(0);
serie.add(generation, best.fitness);
display.setData(best.image.getRaster());
display.getGraphics().drawString(Float.toString(best.fitness), 0, 10);
setTitle("GASimple [" + generation + "]");
revalidate();
repaint();
final Set<Individual> children = new TreeSet<Individual>();
for (int i = 0; i < POP_SIZE; ++i) {
final Individual mother = population.get(rnd.nextInt(POP_SIZE));
final Individual father = population.get(rnd.nextInt(selectCount));
children.add(new Individual(mother, father));
}
population.clear();
population.addAll(children);
++generation;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment