Java 遗传算法:如何实现置换染色体少于n!有效排列

Java 遗传算法:如何实现置换染色体少于n!有效排列,java,graph,permutation,genetic-algorithm,Java,Graph,Permutation,Genetic Algorithm,我目前正在研究一种遗传算法,我想在一个有向、非循环、非状态的图中找到(或近似)最佳排列。一个可能的图可以如下所示: (请注意,多个传入节点意味着多个条件。因此,为了选择G,必须首先选择B和F) 与旅行商问题相反,我的图上并不是所有的节点都是连接的(因此B和E),连接在两个方向上都不起作用(A->B很好,但B->A不可能),并且没有节点可以定义为当前位置(意味着从A到B之后,D仍然是一个有效选项)。因此,在搜索置换以进行适应度计算时,解空间不是n!而是更小(对于上面给出的示例,约145)。 验证

我目前正在研究一种遗传算法,我想在一个有向、非循环、非状态的图中找到(或近似)最佳排列。一个可能的图可以如下所示:

(请注意,多个传入节点意味着多个条件。因此,为了选择G,必须首先选择B和F)

与旅行商问题相反,我的图上并不是所有的节点都是连接的(因此B和E),连接在两个方向上都不起作用(A->B很好,但B->A不可能),并且没有节点可以定义为当前位置(意味着从A到B之后,D仍然是一个有效选项)。因此,在搜索置换以进行适应度计算时,解空间不是n!而是更小(对于上面给出的示例,约145)。 验证置换的规则是“对于位置n处的任何节点,其所有先决条件必须位于小于n的位置”

例如,“A-B-D-C-E-F-H-G-I”将是一个有效的置换,而“I-G-C-H-E-F-D-B-A”将非常无效

有了这些信息,我可以验证适应度函数中的任何给定排列,如果它无效,我可以指定一个值0。然而,我希望在您的帮助下,我可以找到一个更有效的解决方案,因为我正在处理的图可能有大约300个节点,并且所有无效可能性的计算将无法接受所以我想设计一种染色体,对于随机起始群体和进化操作,只有有效的个体被添加到任何给定的群体中

至于测试,我正在使用JGAP库进行Java中的遗传算法和遗传编程,但是这个解决方案的实现不是强制性的

非常感谢您的帮助,请原谅我的任何愚蠢的表达,因为我不是母语人士,也请原谅我在这个问题上的任何愚蠢,因为我对遗传算法相当陌生。

您的图是DAG(有向无环图),正如您所说。此外,连接到节点B的节点A必须位于节点B之前。这基本上是此类图的定义。您只想找到这样一种排序(因为可以有多个排序),它根据您选择的度量值最佳

我提出了一个解决方案

基因型 为图中的每个节点分配一个数字。这些节点的数字将是基因型。因此,对于作为示例发布的图,您将有9个数字。让我们给它一些符号:
K(n)
将是分配给节点的数字
n

解码基因型 要将基因型(一组数字)解码为表型(排序),请遵循以下步骤(基本上是打破领带):

通过这种方式,你总是得到一个有效的解决方案,分配给节点的数字决定了要构造的有效解决方案的数量。你可以愉快地进化这些数字,你将得到不同的顺序

vanilla Khan算法有一个运行时间O(|E |+|V |),即节点数加上图中的边数是线性的。这里我们需要对集合
s
进行排序,因此复杂度会变得更高,这取决于
s
所使用的数据结构。如果它是基于堆的优先级队列,那么(我现在猜测,因为我太懒了,无法计算/证明)O(|E |+|V |*log | V |)。您可能希望尽可能优化此过程,因为它将被称为

备注

这种解码技巧被称为间接编码,也就是说,你进化出的东西不是直接评估的,而是转化成其他的然后评估的东西。这有一个很好的好处,就是总是产生一个有效的解决方案,但它也有一个主要的缺点:基因型的微小变化可能导致表型a的巨大变化反之亦然。这可能会给遗传算法带来困难


我还建议您尝试其他优化框架,而不仅仅是GA,例如..

只是为了帮助我更好地理解,如果解决方案空间很小,为什么要使用GA而不是蛮力?遍历这些图听起来很快。所示的图只是作为一个示例。真正的交易是一个具有相同规则但更开放的图(多个初始可能性和多个死胡同)大约300个节点,这意味着将有300个!排列以检查验证300!只有在节点高度连接以便可以以任何顺序访问它们时才可能。通常有多少个分支退出一个节点?通常是一个或两个,目前最多五个。图形尚未完成,因此可能有超过五个分支的节点在某个时刻退出,但通常是一个或两个。至于进入分支(意味着先决条件)通常是一个,偶尔是两个,到目前为止最多是八个。目前我无法判断这将如何影响遗传算法的可能解决方案,虽然我感谢每一种输入,但遗传算法的解决方案几乎是强制性的(因为这是我的论文,教授希望至少能引入一个令人满意的遗传算法解决方案)好的,我认为像这样约束GA仍然是一个研究问题,而启发式图搜索已经很成熟了,所以我还在探索。但是如果是学校,我知道你没有太多选择。这看起来确实很有帮助,所以首先:非常感谢!为了确保我得到了它:从根节点列表开始,我是一个lisn将从S中选择(其中所有节点都剩下零个传入节点,那么为什么要对其进行排序?可能更愿意将其随机排列?),从S中删除,添加到排序和eac中
input: N is a set of all nodes in the graph
S += {r | r in N && r has no incoming connections }  // a set with the root nodes
I := {n -> |predecessors(n)| | n in N}  // a mapping from the nodes to numbers, the numbers being the numbers of incoming edges to the nodes
ordering := []  // a list of nodes
while |S| > 0  // while the open set is non-empty
    n := arg min_q {K(q) | q in S}  // from the open set, select the node with the lowest assigned number (see above)
    S -= {n}  // remove the node from the open set
    ordering += n  // add the node to the ordering
    for each q in successors(n)
        I[q] -= 1  // decrease the number of incoming nodes for each successor of n
    S += {q | I[q] == 0}  // add all nodes that have no incoming edge left to S
return ordering