在GUI中使用GA

时间:2010-02-18 11:13:58

标签: java genetic-algorithm

很抱歉,如果不清楚这一点,我正在移动设备上写这个并且我正在尝试快速完成。

我编写了一个基本的遗传算法,它使用二进制编码(基因)来构建适应值,并通过使用锦标赛选择,变异和交叉进行多次迭代。作为一个基本的命令行示例,它似乎有效。

我遇到的问题是在GUI中应用遗传算法,因为我正在编写一个使用GA通过迷宫找到方法的迷宫解决程序。如何将随机二进制编码基因和适应度函数(将所有二进制值加在一起)转换为控制迷宫周围机器人的方法?我已经在Java中构建了一个基本的GUI,它包含一个标签迷宫(如网格),可用路径为蓝色,墙壁为黑色。

重申我的GA表现良好并包含任何典型的GA(健身方法,获取和设置人口,选择,交叉等),但现在我需要将其插入GUI以使我的迷宫运行。需要去哪里才能获得可以根据GA所说的不同方向移动的机器人?如果可能的话,粗糙的伪代码会很棒

根据要求,使用单独的类(Indiv)构建Individual,所有主要工作都在Pop类中完成。当一个新个体被实例化时,一组int代表所述个体的基因,从0到1之间的数字随机挑选基因。适应度函数仅将这些基因的值加在一起,并在Pop类处理选择中,两个选定个体的突变和交叉。除此之外没有太多其他内容,命令行程序只显示了n代的进化,每次迭代的总体适应度都在提高。

编辑:现在开始变得更有意义了,虽然有一些事情让我烦恼......

正如Adamski建议我想创建一个“代理”,其中包含如下所示的选项。我遇到的问题是随机位串在这里发挥作用。代理知道墙壁的位置并以4位字符串(即0111)布局,但这对随机32位字符串有何影响? (即10001011011001001110011011010101)如果我有以下迷宫(x是起点,2是目标,1是墙):

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

如果我向左转,我面对错误的方式,如果向前移动,特工将完全从迷宫中移开。我假设第一代字符串将是完全随机的,它会随着适应度的增长而发展,但我不知道字符串在迷宫中是如何工作的。

所以,要做到这一点......

适应性是代理人能够移动并且在墙上的结果。

基因是一串32位,分成16组,每组2位,以显示可用的动作,并且机器人移动这两位需要通过代理四位来显示它靠近墙壁的位置。如果移动是越过墙壁,则移动不会被视为无效,如果移动,并且如果找到新墙,则适应性会上升。

是吗?

2 个答案:

答案 0 :(得分:4)

BadHorse的答案很好,如果你想解决一个特定的迷宫;您只需将您的位串解释为精确指令序列,即可引导代理通过迷宫。在这种情况下,您的适应性不是位串的总和(正如您在问题中所述),而是衡量代理在解决问题方面的成功程度。例如,您的适应度可能被定义为“处理20条指令后,从迷宫末尾直线的距离”。

因此,在评估每个人时,您允许它处理来自您的位串的前20条指令,然后计算其适应性,执行任何交叉/突变,然后创建下一代个体。

如果您希望开发代理以解决任何迷宫,您需要在位字符串中编码规则而不是一系列指令。您可以根据墙壁是紧挨着机器人的前方,左侧还是右侧来定义规则; e.g。

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

这为您提供了一个由16个动作组成的位串,每个动作编码为2位(00 =向前移动,01 =向右转,10 =向左转,11 =向后移动)。在评估代理时,它只是确定其当前状态,并使用位串作为查找表来确定它应该如何响应。然后它会重复这个次数,然后再评估它的适应性。

鉴于此编码,代理可以评估人类通常使用的规则,即“连续跟随左手墙”。显然,如果迷宫未完全连接,这种方法将会失败,在这种情况下,您需要将更多状态编码到基于规则的方法中(例如,如果过了“旧地”,代理可以做出不同的响应)。

希望有所帮助。

修改

回复您的最新修改:

我编写代理“传感器”来检测它是否在墙旁边的事实与位串(你的基因)无关,也许我对我的例子稍微有点困惑。该基因仅编码动作(向前移动等)传感器状态。

因此,在给定传感器读数的特定组合的情况下,您应该编写代码来查找位串的相关部分; 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.
}

鉴于Gene的这个简单定义,您可以将此类嵌入Agent实现中,并记录代理如何使用当前基因“已安装”执行; 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;
  }
}

答案 1 :(得分:0)

如果我理解正确,您需要确定您的机器人在GUI中的操作如何由遗传算法的结果表示?我认为确定您想要使用的表示应该是您的起点。因此,您需要为您个体中的每个(一组)'基因'创建一个映射,以便对您的机器人的运动算法中的某个动作或某个更改进行。

只要您选择了可行的表示形式,实施就会更合乎逻辑。

一个非常简单的运动表现就是让基因硬编码某条路线。您可以使用四个基因的块来表示不同的方向,然后0表示“不沿这个方向移动”而1代表移动。

然后表示01001101可以转换为以下运动模式:

stand still
go one step east
stand still
stand still
go one step north
go one step east
stand still
go one step west