人工蚂蚁问题

人工蚂蚁问题是更为复杂但经典的遗传编程问题,其中进化的个体必须控制一只人工蚂蚁,使其能够吃掉给定环境中所有的食物。这个例子展示了DEAP如何轻松处理更复杂的问题,包括一个复杂的功能和资源系统(包括一个小型模拟器)。

关于此问题的更多信息,请参阅 参考

使用的基本集合

我们使用标准的基本操作集来解决人工蚂蚁问题:

pset = gp.PrimitiveSet("MAIN", 0)
pset.addPrimitive(ant.if_food_ahead, 2)
pset.addPrimitive(prog2, 2)
pset.addPrimitive(prog3, 3)
pset.addTerminal(ant.move_forward)
pset.addTerminal(ant.turn_left)
pset.addTerminal(ant.turn_right)
  • if_food_ahead 是一个原语,如果蚂蚁前方有食物,则执行其第一个参数;否则,执行其第二个参数。

  • prog2()prog3() 相当于 lisp 的 PROGN2 和 PROGN3 函数。它们按顺序执行其子节点,从第一个到最后一个。例如,prog2 将首先执行其第一个参数,然后执行其第二个参数。

  • move_forward() 使人工蚂蚁向前移动一步。这是一个终端。

  • turn_right()turn_left() 使人工蚂蚁顺时针和逆时针转动,而不改变其位置。这些也是终端。

备注

与符号回归或奇偶校验不同,这里没有外部输入。

尽管这些功能显然不是Python内置的,但定义它们非常容易:

def progn(*args):
    for arg in args:
        arg()

def prog2(out1, out2): 
    return partial(progn,out1,out2)

def prog3(out1, out2, out3):     
    return partial(progn,out1,out2,out3)

def if_then_else(condition, out1, out2):
    out1() if condition() else out2()

class AntSimulator(object):
    def if_food_ahead(self, out1, out2):
        return partial(if_then_else, self.sense_food, out1, out2)

部分函数是 Python 的一个强大功能,它允许动态创建函数。如需更详细的信息,请参阅 Python 文档中的 functools.partial()

评估函数

评估函数使用模拟器类的一个实例来评估个体。每个个体在模拟器地图上被给予600次移动(地图从外部文件获取)。每个个体的适应度对应于拾取的食物数量。在这个例子中,我们使用的是经典的轨迹,即*Santa Fe轨迹*,其中有89块食物。因此,一个完美的个体会达到89的适应度。

def evalArtificialAnt(individual):
    # Transform the tree expression to functional Python code
    routine = gp.compile(individual, pset)
    # Run the generated routine
    ant.run(routine)
    return ant.eaten,

其中 ant 是使用的模拟器实例。evaluate() 函数是 DEAP 提供的一个便利函数,它从 GP 个体及其原始函数集中返回一个可执行的 Python 程序。

完整示例

除了模拟器代码(约75行),代码在本质上与 符号回归示例 没有根本区别。请注意,由于问题更复杂,通过将锦标赛规模增加到7来提高选择压力,可以实现更好的性能。

完整的 examples/gp/ant

参考

John R. Koza, “遗传编程I:通过自然选择对计算机进行编程”, MIT Press, 1992, 第147-161页.