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); } } }
/** Mutates the chromsome based on the set of probabilities. */ public Chromosome mutate(Chromosome mutatee) { Gene[] genes = mutatee.genes(); int originalSize = genes.length; NEATChromosome mutated; int i; for (i = 0; i < genes.length; i++) { if (genes[i] instanceof NEATLinkGene) { genes[i] = this.mutateLink((NEATLinkGene) genes[i]); } else if (genes[i] instanceof NEATNodeGene) { genes[i] = this.mutateNode((NEATNodeGene) genes[i]); } else if (genes[i] instanceof NEATFeatureGene) { genes[i] = this.mutateFeature((NEATFeatureGene) genes[i]); } } mutated = new NEATChromosome(genes); mutated.setSpecieId(((NEATChromosome) mutatee).getSpecieId()); this.mutateAddLink(mutated); this.mutateAddNode(mutated); // now update chrome for depth and recurrency legality this.updateDepthInfo(mutated); mutated.updateChromosome(this.ensureLegalLinks(mutated.genes())); if (mutated.genes().length < originalSize) { System.out.println( "Mutation -- Original: " + originalSize + " new: " + mutated.genes().length); } return (mutated); }
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 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 int findChosenIndex(NEATLinkGene chosen, Chromosome mutatee) { int idx = -1; int i = 0; Gene[] genes = mutatee.genes(); int mutateeSize = genes.length; while (i < mutateeSize && idx == -1) { if (genes[i] instanceof NEATLinkGene && ((NEATLinkGene) genes[i]).getFromId() == chosen.getFromId() && ((NEATLinkGene) genes[i]).getToId() == chosen.getToId()) { idx = i; } else { i++; } } return (idx); }
private void updateDepthInfo(Chromosome mutated) { // use descriptor's chromo to create net ArrayList nodes = new ArrayList(); ArrayList links = new ArrayList(); int i; Gene[] genes = mutated.genes(); for (i = 0; i < genes.length; i++) { if (genes[i] instanceof NEATNodeGene) { nodes.add(genes[i]); } else if (genes[i] instanceof NEATLinkGene) { if (((NEATLinkGene) genes[i]).isEnabled()) { // only add enabled links to the net structure links.add(genes[i]); } } } this.assignNeuronDepth(this.findOutputNodes(this.candidateNodes(genes)), 1, mutated); }