Мой код на самом деле не делает этого как таковой, а скорее находит все возможные грани, которые можно добавить без создания цикла. Возвращаемое значение функции FindNodesToConnect — это карта, где ключ — это узел, а значение — это список всех узлов, к которым мы можем направить ребро от ключа без введения циклов.
Еще одна причуда заключается в том, что это не отдельная функция, а часть более крупного проекта нейроэволюции, поэтому входными данными является не график, а геном, в котором закодирован график, однако геном немедленно транслируется в другой структуры данных, поэтому никаких предварительных знаний не требуется (но при необходимости я был бы рад уточнить детали).
Меня больше всего беспокоит спектакль, эта функция может вызываться сотни раз в каждом поколении для сотен или тысяч поколений, но она содержит вложенные циклы и рекурсивную функцию. Есть ли способ это оптимизировать? или, может быть, совсем другой способ сделать это?
Еще один второстепенный момент: читаемость что я всегда пытаюсь улучшить.
Код:
'use strict';
if (!window.Neat) window.Neat = {};
Neat.GenomeGraph = (function () {
const genomeToNodeMap = genome => {
// return value is a map that maps every node to its direct predecessors
const result = new Map()
for (let nodeGene of genome.nodeGenes)
result.set(nodeGene.id, [])
for (let connectionGene of genome.connectionGenes)
result.get(connectionGene.outId).push(connectionGene.inId)
return result
}
const getDependencies = (nodeMap, nodeId) => {
// return value is all the predecessors of a node (found recursively)
return [].concat.apply(nodeMap.get(nodeId), nodeMap.get(nodeId).map(nextNodeId => getDependencies(nodeMap, nextNodeId)))
}
const setDifference = (A, B) => A.filter(x => !B.includes(x))
return {
FindNodesToConnect: genome => {
const nodeMap = genomeToNodeMap(genome)
const graphNodes = genome.nodeGenes.map(nodeGene => nodeGene.id)
const result = new Map()
for (let currentNodeId of graphNodes) {
const cannotConnectTo = getDependencies(nodeMap, currentNodeId);
cannotConnectTo.push(currentNodeId)
for (let [nodeId, dep] of nodeMap)
if (dep.includes(currentNodeId))
cannotConnectTo.push(nodeId)
const canConnectTo = setDifference(graphNodes, cannotConnectTo)
if (canConnectTo.length > 0)
result.set(currentNodeId, canConnectTo)
}
return result;
}
}
})()
Пример вызова функции:
Neat.GenomeGraph.FindNodesToConnect({
nodeGenes: [1, 2, 3, 4, 5, 6, 7].map(x => ({ id: x })),
connectionGenes: [
{ inId: 1, outId: 2},
{ inId: 2, outId: 3},
{ inId: 3, outId: 6},
{ inId: 5, outId: 6},
{ inId: 4, outId: 3},
{ inId: 4, outId: 7},
]
})
