private void assignNeuronDepth(Gene[] nodeGenes, int depth, Chromosome mutated) { int i; NEATNodeGene node; // ArrayList nodeGenes = this.findOutputNodes(this.candidateNodes(genes)); for (i = 0; i < nodeGenes.length; i++) { node = (NEATNodeGene) nodeGenes[i]; if (node.getType() == NEATNodeGene.OUTPUT) { if (depth == 1) { node.setDepth(depth); this.assignNeuronDepth( this.findSourceNodes(node.id(), mutated.genes()), depth + 1, mutated); } } else if (node.getType() == NEATNodeGene.HIDDEN) { if (node.getDepth() == 0) { // we have an unassigned depth node.setDepth(depth); this.assignNeuronDepth( this.findSourceNodes(node.id(), mutated.genes()), depth + 1, mutated); } } else if (node.getType() == NEATNodeGene.INPUT) { node.setDepth(Integer.MAX_VALUE); } } }
private NEATNodeGene findNode(int id, Gene[] genes) { int i = 0; Gene gene; NEATNodeGene node = null; boolean found = false; while (i < genes.length && !found) { gene = genes[i]; if (gene instanceof NEATNodeGene) { node = (NEATNodeGene) genes[i]; if (node.id() == id) { found = true; } } i++; } return (node); }
private void mutateAddNode(Chromosome mutatee) { double nodeRandVal = nodeRand.nextDouble(); ArrayList nodeLinks; // ArrayList nodes; NEATLinkGene chosen; NEATNodeGene newNode; NEATLinkGene newLower; NEATLinkGene newUpper; int newChromoIdx = mutatee.genes().length; // Gene[] newChromo = new Gene[newChromoIdx + 3]; Gene[] newChromo = new Gene[newChromoIdx + 2]; System.arraycopy(mutatee.genes(), 0, newChromo, 0, newChromoIdx); int linkIdx; if (nodeRandVal < this.pAddNode) { // add a node on an existing enabled connection // find an existing connection to intercept nodeLinks = this.candidateLinks(mutatee.genes(), true); if (nodeLinks.size() > 0) { // ensure there is a link to split linkIdx = nodeRand.nextInt(nodeLinks.size()); chosen = (NEATLinkGene) nodeLinks.get(linkIdx); // disable old link chosen.setEnabled(false); newNode = InnovationDatabase.database().submitNodeInnovation(chosen); // newNode.setBias(MathUtils.nextPlusMinusOne()); newLower = InnovationDatabase.database().submitLinkInnovation(chosen.getFromId(), newNode.id()); newUpper = InnovationDatabase.database().submitLinkInnovation(newNode.id(), chosen.getToId()); // set weights according to Stanley et al's NEAT document newLower.setWeight(1); newUpper.setWeight(chosen.getWeight()); // now update the chromosome with new node and 2 new links newChromo[this.findChosenIndex(chosen, mutatee)] = newNode; // newChromo[newChromoIdx++] = newNode; newChromo[newChromoIdx++] = newLower; newChromo[newChromoIdx] = newUpper; mutatee.updateChromosome(newChromo); } } }
private Gene[] findOutputNodes(ArrayList nodes) { ArrayList outputNodes = new ArrayList(); Gene[] nodeGenes; NEATNodeGene node; int i; for (i = 0; i < nodes.size(); i++) { node = (NEATNodeGene) nodes.get(i); if (node.getType() == NEATNodeGene.OUTPUT) { outputNodes.add(node); } } nodeGenes = new NEATNodeGene[outputNodes.size()]; for (i = 0; i < nodeGenes.length; i++) { nodeGenes[i] = (NEATNodeGene) outputNodes.get(i); } return (nodeGenes); }
private boolean linkIllegal(NEATNodeGene from, NEATNodeGene to, ArrayList links) { boolean illegal = false; int idx = 0; NEATLinkGene linkGene; if ((to.getType() == NEATNodeGene.INPUT)) { illegal = true; } else { while (!illegal && (idx < links.size())) { linkGene = (NEATLinkGene) links.get(idx); // if ((linkGene.getFromId() == from.id() && linkGene.getToId() == to.id()) || // ((to.getDepth() <= from.getDepth()) && !this.recurrencyAllowed)) { if ((linkGene.getFromId() == from.id() && linkGene.getToId() == to.id())) { illegal = true; } idx++; } } return (illegal); }
private Gene[] ensureLegalLinks(Gene[] genes) { ArrayList links; NEATLinkGene link; NEATNodeGene from; NEATNodeGene to; Gene[] newGenes = null; ArrayList tmpGenes = new ArrayList(); int i; // only need to prune if recurrency not allowed if (!this.recurrencyAllowed) { // only return enabled links links = this.candidateLinks(genes, false); for (i = 0; i < genes.length; i++) { if (genes[i] instanceof NEATLinkGene) { link = (NEATLinkGene) genes[i]; from = this.findNode(link.getFromId(), genes); to = this.findNode(link.getToId(), genes); if (from.getDepth() > to.getDepth()) { // not recurrent - so keep tmpGenes.add(genes[i]); } } else { tmpGenes.add(genes[i]); } } newGenes = new Gene[tmpGenes.size()]; for (i = 0; i < newGenes.length; i++) { newGenes[i] = (Gene) tmpGenes.get(i); } } else { newGenes = genes; } return (newGenes); }
private void mutateAddLink(Chromosome mutatee) { double linkRandVal = linkRand.nextDouble(); NEATNodeGene from; NEATNodeGene to; int rIdx; int i = 0; ArrayList links; ArrayList nodes; Gene[] genes = new Gene[mutatee.size() + 1]; System.arraycopy(mutatee.genes(), 0, genes, 0, mutatee.genes().length); Gene newLink = null; if (linkRandVal < this.pAddLink) { nodes = this.candidateNodes(mutatee.genes()); links = this.candidateLinks(mutatee.genes(), false); // find a new available link while (newLink == null && i < MAX_LINK_ATTEMPTS) { rIdx = linkRand.nextInt(nodes.size()); from = ((NEATNodeGene) nodes.get(rIdx)); rIdx = linkRand.nextInt(nodes.size()); to = ((NEATNodeGene) nodes.get(rIdx)); // TODO Remove if (from.getInnovationNumber() == 2 && to.getInnovationNumber() == 5) { System.out.println("a"); } if (!this.linkIllegal(from, to, links)) { // set it to a random value newLink = InnovationDatabase.database().submitLinkInnovation(from.id(), to.id()); ((NEATLinkGene) newLink).setWeight(MathUtils.nextPlusMinusOne()); // add link between 2 unconnected nodes genes[genes.length - 1] = newLink; mutatee.updateChromosome(genes); } i++; } } }
private Gene mutateNode(NEATNodeGene mutatee) { double perturbRandVal = perturbRand.nextDouble(); double mutateBias = perturbRand.nextDouble(); NEATNodeGene mutated = mutatee; double newSF = mutatee.sigmoidFactor(); double newBias = mutatee.bias(); if (perturbRandVal < this.pPerturb) { newSF = mutatee.sigmoidFactor() + MathUtils.nextClampedDouble(-perturb, perturb); mutated = new NEATNodeGene( mutated.getInnovationNumber(), mutated.id(), newSF, mutated.getType(), mutated.bias()); } if (mutateBias < this.pMutateBias) { newBias += MathUtils.nextClampedDouble(-biasPerturb, biasPerturb); mutated = new NEATNodeGene( mutated.getInnovationNumber(), mutated.id(), mutated.sigmoidFactor(), mutated.getType(), newBias); } return (mutated); }