我们如何在遗传编程中实现循环结构?
How can we implement loop constructs in genetic programming?
我研究遗传编程有一段时间了,开始想知道如何实现循环结构。
在 for 循环的情况下,我可以想到 3 个参数:
- start:计数器的起始值
- end:计数器上限
- expression: while counter < end
要执行的表达式
现在棘手的部分是 expression 因为它在每次迭代中生成相同的值,除非 counter 以某种方式注入其中。所以我可以允许 counter 的符号出现在表达式中,但是我如何防止它出现在 for 循环之外?
另一个问题是使用表达式的结果。我可以有一个对结果求和的 for 循环,另一个将它们相乘的循环,但这是限制性的,而且似乎不正确。我想要一个通用的解决方案,而不是针对每个操作员的解决方案。
那么有谁知道在遗传编程中实现循环的好方法吗?
嗯,这很棘手。遗传编程(最初的 Koza 风格 GP)最适合函数式编程,即没有内部执行状态,每个节点都是一个 returns(并且可能采用)值的函数,如 lisp。当节点是某个循环时,这是一个问题 - 不清楚节点应该 return.
您也可以将循环节点设计为二进制节点。一个参数是一个布尔表达式,将在每次循环之前调用,如果 returned 为真,则将执行循环。第二个参数是循环表达式。
你已经提到的问题,就是没有办法改变循环表达式。您可以通过引入一些内部状态或变量的概念来解决这个问题。但这给您留下了另一个问题,比如需要定义变量的数量。可以实现一个变量,例如通过一个函数元组 - setter(一个参数,没有 return 值,或者它可以 return 参数)和 getter(没有参数,return s 变量的值)。
关于循环结果处理的方式,可以从GP一步到强类型GP或者简称STGP。它本质上是一个有类型的 GP。然后,您的循环可以有效地成为一个 return 值列表(例如数字)的函数,并且您可以使用其他函数来获取此类列表并计算其他值...
还有另一种 GP 算法(我最喜欢的),称为语法进化(或 GE),它使用上下文无关语法来生成程序。它可以像 STGP 一样用于编码类型信息。您还可以以一种可以生成类似 c 的经典 for 和 while 循环的方式来定义语法。它的一些扩展,如动态定义函数,可用于动态实现变量。
如果有什么不清楚的地方,请评论答案,我会尽力澄清。
zegkjan 的回答的问题是剥猫皮的方法不止一种。
实际上有一种比 koza 树更简单、有时更好的创建 GP 数据结构的解决方案,而不是使用堆栈。
这个方法叫做Stack Based Genetic Programming,已经很老了(1993)。这种遗传编程方法完全移除了树,你有一个指令列表和一个数据堆栈(你的功能和终端集保持不变)。您遍历指令列表,将值推送到数据堆栈,然后拉取值以使用它们,并根据您的指令将新的 value/values 返回到堆栈。例如,考虑以下遗传程序。
0: PUSH TERMINAL X
1: PUSH TERMINAL X
2: MULTIPLY (A,B)
迭代这个程序会给你:
step1: DATASTACK X
step2: DATASTACK X, X
step3: DATASTACK X^2
一旦你执行了所有程序列表语句,你就可以从堆栈中取出你关心的元素数量(你可以通过这种方式从 GP 程序中获取多个值)。这最终成为一种快速且极其灵活的方法(内存位置、参数数量无关紧要,返回的元素数量也不重要)您可以相当快速地实施。
要在这个方法中循环,你可以创建一个单独的堆栈,一个执行堆栈,其中使用新的特殊运算符来一次从执行堆栈中压入和弹出多个语句,以便随后执行。
此外,您可以简单地包含一个跳转语句以在您的程序列表中向后移动,制作一个循环语句,或者有一个单独的堆栈保存循环信息。有了这个,遗传程序理论上可以开发自己的 for 循环。
0: PUSH TERMINAL X
1: START_LOOP 2
2: PUSH TERMINAL X
3: MULTIPLY (A, B)
4: DECREMENT_LOOP_NOT_ZERO
step1: DATASTACK X
LOOPSTACK
step2: DATASTACK X
LOOPSTACK [1,2]
step3: DATASTACK X, X
LOOPSTACK [1,2]
step4: DATASTACK X^2
LOOPSTACK [1,2]
step5: DATASTACK X^2
LOOPSTACK [1,1]
step6: DATASTACK X^2, X
LOOPSTACK [1,1]
step7: DATASTACK X^3
LOOPSTACK [1,1]
step8: DATASTACK X^3
LOOPSTACK [1,0]
但是请注意,使用任何方法,GP 程序都可能很难真正进化出具有循环的成员,即使进化了,这种机制也可能导致在一开始,可能会以任何方式将其从人口中移除。要解决此类问题(可能好的创新会因早期健康状况不佳而早早夭折),您需要在遗传计划中包含 demes 的概念,以隔离遗传上不同的人群。
我研究遗传编程有一段时间了,开始想知道如何实现循环结构。
在 for 循环的情况下,我可以想到 3 个参数:
- start:计数器的起始值
- end:计数器上限
- expression: while counter < end 要执行的表达式
现在棘手的部分是 expression 因为它在每次迭代中生成相同的值,除非 counter 以某种方式注入其中。所以我可以允许 counter 的符号出现在表达式中,但是我如何防止它出现在 for 循环之外?
另一个问题是使用表达式的结果。我可以有一个对结果求和的 for 循环,另一个将它们相乘的循环,但这是限制性的,而且似乎不正确。我想要一个通用的解决方案,而不是针对每个操作员的解决方案。
那么有谁知道在遗传编程中实现循环的好方法吗?
嗯,这很棘手。遗传编程(最初的 Koza 风格 GP)最适合函数式编程,即没有内部执行状态,每个节点都是一个 returns(并且可能采用)值的函数,如 lisp。当节点是某个循环时,这是一个问题 - 不清楚节点应该 return.
您也可以将循环节点设计为二进制节点。一个参数是一个布尔表达式,将在每次循环之前调用,如果 returned 为真,则将执行循环。第二个参数是循环表达式。
你已经提到的问题,就是没有办法改变循环表达式。您可以通过引入一些内部状态或变量的概念来解决这个问题。但这给您留下了另一个问题,比如需要定义变量的数量。可以实现一个变量,例如通过一个函数元组 - setter(一个参数,没有 return 值,或者它可以 return 参数)和 getter(没有参数,return s 变量的值)。
关于循环结果处理的方式,可以从GP一步到强类型GP或者简称STGP。它本质上是一个有类型的 GP。然后,您的循环可以有效地成为一个 return 值列表(例如数字)的函数,并且您可以使用其他函数来获取此类列表并计算其他值...
还有另一种 GP 算法(我最喜欢的),称为语法进化(或 GE),它使用上下文无关语法来生成程序。它可以像 STGP 一样用于编码类型信息。您还可以以一种可以生成类似 c 的经典 for 和 while 循环的方式来定义语法。它的一些扩展,如动态定义函数,可用于动态实现变量。
如果有什么不清楚的地方,请评论答案,我会尽力澄清。
zegkjan 的回答的问题是剥猫皮的方法不止一种。
实际上有一种比 koza 树更简单、有时更好的创建 GP 数据结构的解决方案,而不是使用堆栈。
这个方法叫做Stack Based Genetic Programming,已经很老了(1993)。这种遗传编程方法完全移除了树,你有一个指令列表和一个数据堆栈(你的功能和终端集保持不变)。您遍历指令列表,将值推送到数据堆栈,然后拉取值以使用它们,并根据您的指令将新的 value/values 返回到堆栈。例如,考虑以下遗传程序。
0: PUSH TERMINAL X
1: PUSH TERMINAL X
2: MULTIPLY (A,B)
迭代这个程序会给你:
step1: DATASTACK X
step2: DATASTACK X, X
step3: DATASTACK X^2
一旦你执行了所有程序列表语句,你就可以从堆栈中取出你关心的元素数量(你可以通过这种方式从 GP 程序中获取多个值)。这最终成为一种快速且极其灵活的方法(内存位置、参数数量无关紧要,返回的元素数量也不重要)您可以相当快速地实施。
要在这个方法中循环,你可以创建一个单独的堆栈,一个执行堆栈,其中使用新的特殊运算符来一次从执行堆栈中压入和弹出多个语句,以便随后执行。
此外,您可以简单地包含一个跳转语句以在您的程序列表中向后移动,制作一个循环语句,或者有一个单独的堆栈保存循环信息。有了这个,遗传程序理论上可以开发自己的 for 循环。
0: PUSH TERMINAL X
1: START_LOOP 2
2: PUSH TERMINAL X
3: MULTIPLY (A, B)
4: DECREMENT_LOOP_NOT_ZERO
step1: DATASTACK X
LOOPSTACK
step2: DATASTACK X
LOOPSTACK [1,2]
step3: DATASTACK X, X
LOOPSTACK [1,2]
step4: DATASTACK X^2
LOOPSTACK [1,2]
step5: DATASTACK X^2
LOOPSTACK [1,1]
step6: DATASTACK X^2, X
LOOPSTACK [1,1]
step7: DATASTACK X^3
LOOPSTACK [1,1]
step8: DATASTACK X^3
LOOPSTACK [1,0]
但是请注意,使用任何方法,GP 程序都可能很难真正进化出具有循环的成员,即使进化了,这种机制也可能导致在一开始,可能会以任何方式将其从人口中移除。要解决此类问题(可能好的创新会因早期健康状况不佳而早早夭折),您需要在遗传计划中包含 demes 的概念,以隔离遗传上不同的人群。