"程序编写程序"的一个尝试:遗传编程

本文最早发表本人博客:http://www.gotoli.us/?p=1773

遗传编程是遗传算法另一个重要的后续工作。顾名思义,遗传编程中的一个个体代表了解决某个问题的候选程序,遗传编程模拟自然选择挑选出正确的程序。遗传编程是人类追求自动编程的一次尝试。遗传编程的两个重要概念是基因型和表现型。基因型就是种群个体的编码;表现型是种群个体所表示的程序片段。其实遗传算法就有这两个概念的萌芽。遗传编程之所以会强调这两个概念,因为遗传编程很难直接处理程序片段(表现型),反而容易处理程序片段的内在结构(基因型)。根据基因型形态的不同,遗传编程方法可以分为三种:线性遗传编程、基于树的遗传编程和基于图的遗传编程。

1 . 线性遗传编程

线性遗传编程有广义和狭义之分。广义线性遗传编程将候选程序编码进定长或者变长的字符串,即基因型是线性字符串。狭义线性遗传编程中的候选程序是汇编语言或者高级编程语言程序。一个狭义线性遗传编程的个体可以是一段简单 C 语言指令。这些指令作用在一个或者两个预习定义的变量或者常量上(变量数量一般为指令个数的4倍)。下图是一个狭义线性遗传编程候选程序的示例。

除了狭义线性遗传编程之外,广义线性遗传编程还包括:Multi-Expression Programming (MEP), Grammatical Evolution (GE), Gene Expression Programming (GEP), Cartesian Genetic Programming (CGP),和 Genetic Algorithm for Deriving Software (GADS)。其中我们就介绍一下适合电路设计的笛卡尔遗传编程 (Cartesian Genetic Programming, CGP)。比如我们要用两个加操作两个减操作和两个乘操作得到如下运算。

笛卡尔遗传编程将下面的一个候选程序编写进字符串"001 100 131 201 044 254 2573"。字符串中的三位数字“xyz"表示x操作的输入是y和z两个连线,字符串中最后的四位数字"opqr"表示输出opqr四个连线。笛卡尔遗传编程只用变异操作,而不用交叉操作。

Paste_Image.png

对线性遗传编程感兴趣的同学可以阅读论文 Oltean et al. (2003)。

2 . 基于树的遗传编程。

基于树的遗传编程的基因型是树结构。基于树的遗传编程是遗传编程最早的形态,也是遗传编程的主流方法。在之前的博客“欺骗”深度学习的遗传算法中正则表达式生成问题用的就是基于树的遗传编程。基于树的遗传编程的交叉操作如下所示,两个颗树之间随机交换子树。

基于树的遗传编程的变异操作有两种:一种是随机变换树中的符号或者操作符,另一种是随机变换子树。下图左下角是变换符号或者操作符的结果,右下角是变换子树的结果。

上面的树结构(基因型)都是表达了一个数学公式,我们在树结构上定义一下语法操作符,便可以表达一段程序了。比如,下图是定义了CL操作符之后,For循环的树结构。

3 .基于图的遗传编程。

树是一种特殊的图,因此人们很自然地想到将基于树的遗传编程扩展到基于图的遗传编程。下图就是基于图的遗传编程的基因型的一个示例。

也有人将笛卡尔遗传编程归入基于图的遗传编程,这里,我们将所有基因型是线性字符串的遗传编程归入线性遗传编程类别。

遗传编程是人类实现“程序编写程序”的一次尝试。但到目前为止,遗传编程大体上依然只是实验室里好玩的 toy system。


参考文献


Oltean, Mihai, and Crina Grosan. "A comparison of several linear genetic programming techniques." Complex Systems 14.4 (2003): 285-314.

你可能感兴趣的:("程序编写程序"的一个尝试:遗传编程)