views:

208

answers:

2
+2  Q: 

Using GA in GUI

Sorry if this isn't clear as I'm writing this on a mobile device and I'm trying to make it quick.

I've written a basic Genetic Algorithm with a binary encoding (genes) that builds a fitness value and evolves through several iterations using tournament selection, mutation and crossover. As a basic command-line example it seems to work.

The problem I've got is with applying a genetic algorithm within a GUI as I am writing a maze-solving program that uses the GA to find a method through a maze. How do I turn my random binary encoded genes and fitness function (add all the binary values together) into a method to control a bot around a maze? I have built a basic GUI in Java consisting of a maze of labels (like a grid) with the available routes being in blue and the walls being in black.

To reiterate my GA performs well and contains what any typical GA would (fitness method, get and set population, selection, crossover, etc) but now I need to plug it into a GUI to get my maze running. What needs to go where in order to get a bot that can move in different directions depending on what the GA says? Rough pseudocode would be great if possible

As requested, an Individual is built using a separate class (Indiv), with all the main work being done in a Pop class. When a new individual is instantiated an array of ints represent the genes of said individual, with the genes being picked at random from a number between 0 and 1. The fitness function merely adds together the value of these genes and in the Pop class handles selection, mutation and crossover of two selected individuals. There's not much else to it, the command line program just shows evolution over n generations with the total fitness improving over each iteration.

EDIT: It's starting to make a bit more sense now, although there are a few things that are bugging me...

As Adamski has suggested I want to create an "Agent" with the options shown below. The problem I have is where the random bit string comes into play here. The agent knows where the walls are and has it laid out in a 4 bit string (i.e. 0111), but how does this affect the random 32 bit string? (i.e. 10001011011001001010011011010101) If I have the following maze (x is the start place, 2 is the goal, 1 is the wall):

x 1 1 1 1
0 0 1 0 0
1 0 0 0 2

If I turn left I'm facing the wrong way and the agent will move completely off the maze if it moves forward. I assume that the first generation of the string will be completely random and it will evolve as the fitness grows but I don't get how the string will work within a maze.

So, to get this straight...

The fitness is the result of when the agent is able to move and is by a wall.

The genes are a string of 32 bits, split into 16 sets of 2 bits to show the available actions and for the robot to move the two bits need to be passed with four bits from the agent showings its position near the walls. If the move is to go past a wall the move isn't made and it is deemed invalid and if the move is made and if a new wall is found then the fitness goes up.

Is that right?

A: 

If I understand correctly, you need to determine how the actions of your bot in the GUI are represented by the outcome of your genetic algorithm? I think that determining the representation that you want to use should be your starting point. So you need to create a mapping for each (group of) 'genes' in your individual to a certain action or a certain change in the movement algorithm of your bot.

As soon as you've chosen a viable representation, the implementation will be somewhat more logical.

A very simple representation of movement would be to let the genes hard-code a certain route. You can use blocks of four genes to represent the different directions, and then a 0 represents 'don't move in this direction' and a 1 represents moving.

Then the representation 01001101 could be translated as the following movement pattern:

stand still
go one step east
stand still
stand still
go one step north
go one step east
stand still
go one step west
Josien
+3  A: 

BadHorse's answer is good if you want to solve a specific maze; you simply intepret your bit string as a sequence of precise instructions to guide the agent through the maze. In this case your fitness is not the sum of the bit string (as you state in your question) but rather some metric measuring how successfull the agent was in solving the problem. For example, your fitness might be defined as "distance in a straight line from end of maze after processing 20 instructions".

Hence, when evaluating each individual you allow it to process the first 20 instructions from your bit string and then compute its fitness, perform any crossovers / mutations and then create the next generation of individuals.

If you wish to develop your agent to solve any maze you need to encode rules within your bit string rather than a sequence of instructions. You could define rules based on whether a wall was immediately behind, in front, left or right of the robot; e.g.

FBLR Action
0000 Move Forward
0001 Move Forward
0010 Turn Right
etc

This gives you a bit string consisting of 16 actions, each action encoded as 2 bits (00 = Move Forward, 01 = Turn Right, 10 = Turn Left, 11 = Move Backwards). When evaluating your agent it simply determines its current state and uses the bit string as a lookup table to determine how it should respond. It then repeats this a certain number of times after which point you evaluate its fitness.

Given this encoding the agent could evaluate the rule humans typically use which is "Follow the left hand wall continuously". Obviously this approach will fail if the maze is not fully connected and in this case you need to encode more state into your rules based approach (e.g. the agent could respond differently if going over "old ground").

Hope that helps.

EDIT

In response to your latest edit:

The fact that I've encoded the agent "sensors" detecting whether it is next to a wall or not isn't relevant to the bit string (your gene), and perhaps I've slightly confused things with my example. The gene only encodes the actions (move forward, etc.) not the sensor states.

You should therefore write code to look-up the relevant part of the bit string given a particular combination of sensor readings; e.g.

/**
 * Enumeration describing the four available actions to the agent
 * and methods for decoding a given action from the "bit" string
 * (actually represented using booleans).
 */
public enum Action {
  MOVE_FORWARD, REVERSE, TURN_LEFT, TURN_RIGHT

  Action decodeAction(boolean b1, boolean b2) {
    Action ret;

    if (b1) {
      ret = b2 ? Action.MOVE_FORWARD : Action.TURN_LEFT;
    } else {
      ret = b2 ? Action.TURN_RIGHT : Action.REVERSE;
    }

    return ret;
  }
}

/**
 * Class encapsulating the 32-bit "bit string" represented using booleans.
 * Given the state of the four agent inputs the gene will provide a specific
 * action for the agent to perform.
 */
public class Gene {
  private final boolean[] values = new boolean[32];

  public Action getActionForSensorInputs(boolean wallInFront,
    boolean wallBehind, boolean wallToLeft, boolean wallToRight) {

    int i=0;

    // Encode the four sensor inputs as a single integer value by
    // bitwise-ORing each sensor value with a power of 2.
    // The encoded value will be in the range [0, 15].
    if (wallToRight) {
      i |= 0x01;
    }

    if (wallToLeft) {
      i |= 0x02;
    }

    if (wallBehind) {
      i |= 0x04;
    }

    if (wallInFront) {
      i |= 0x08;
    }

    // The look-up index is i * 2 because each action is encoded as 2
    // booleans.
    int index = i * 2;

    // Retrieve the two action bits from the bit string.
    boolean b1 = this.values[index];
    boolean b2 = this.values[index + 1];

    // Finally decode the action to perform.
    return Action.decodeAction(b1, b2);
  }

  // TODO: Add method to support crossover and mutation with other Genes.
}

Given this simple definition of a Gene you could embed this class within an Agent implementation and record how the agent performs with the current gene "installed"; e.g.

private enum Direction { NORTH, SOUTH, EAST, WEST };

public class Agent {
  private final Geneva gene;
  private final int x; // x position in maze;
  private final int y; // y position in maze;
  private Direction currentDirection;

  public double evaluate() {
    double fitness;

    // Perform up to 20 actions and then evaluate fitness.
    for (int i=0; i<20; ++i) {
      // TODO Determine sensor inputs.

      Action action = gene.getActionForSensorInputs(...);

      // TODO: Now apply action to update agent's state.
      // If agent has reached goal exit loop and return fitness 1.0 (max fitness).
      // If agent has exited the maze then exit loop and return 0.0 (min fitness).
    }

    // Calculate fitness after 100 steps taken.  For example could be
    // calculated as sqrt((goal.x - x) ^ 2 + (goal.y - y) ^ 2).

    return fitness;
  }
}
Adamski
The latter part is how I want to do it, so it will solve any given maze using rules. The part I have trouble with is assigning the rules. As I understand it the agent will have its own "lookup" with the values you've given at the top, and then a string of 32 bits, split into 16 sets of 2 bits (actions) is gained from the genes, with four actions available. I've edited the question to show where I am having troubles so that I won't run out of space here..
AlexT
@AlexT: Sorry for the delay; I've edited my answer and added some sample code to get you started.
Adamski
This looks great so far! I'm going to toy with the code for a bit and try and build a Maze class then if everything goes as planned I'll come back and accept this answer.
AlexT
Ok no worries. Be aware that I put the code together very quickly and haven't tested it. Also, remember that because there's no "memory" encoded into each state (e.g. previous 3 squares) the solving power of the solution will be fairly limited, but I think it's a good place to start.
Adamski