package org.encog.neural.hyperneat;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.encog.engine.network.activation.ActivationFunction;
import org.encog.engine.network.activation.ActivationSteepenedSigmoid;
import org.encog.ml.MLMethod;
import org.encog.ml.data.MLData;
import org.encog.ml.data.basic.BasicMLData;
import org.encog.ml.ea.codec.GeneticCODEC;
import org.encog.ml.ea.genome.Genome;
import org.encog.ml.genetic.GeneticError;
import org.encog.neural.hyperneat.substrate.Substrate;
import org.encog.neural.hyperneat.substrate.SubstrateLink;
import org.encog.neural.hyperneat.substrate.SubstrateNode;
import org.encog.neural.neat.NEATCODEC;
import org.encog.neural.neat.NEATLink;
import org.encog.neural.neat.NEATNetwork;
import org.encog.neural.neat.NEATPopulation;

public class HyperNEATCODEC implements GeneticCODEC {

	private double minWeight = 0.2;
	private double maxWeight = 5.0;
	
	@Override
	public MLMethod decode(Genome genome) {
		// obtain the CPPN
		NEATCODEC neatCodec = new NEATCODEC();
		NEATNetwork cppn = (NEATNetwork) neatCodec.decode(genome);

		// create the phenotype
		NEATPopulation pop = (NEATPopulation) genome.getPopulation();
		Substrate substrate = pop.getSubstrate();

		List<NEATLink> linkList = new ArrayList<NEATLink>();
		
		ActivationFunction[] afs = new ActivationFunction[substrate
				.getNodeCount()];

		ActivationFunction af = new ActivationSteepenedSigmoid();
		// all activation functions are the same
		for (int i = 0; i < afs.length; i++) {
			afs[i] = af;
		}
		
		double c = this.maxWeight / (1.0 - this.minWeight);

		// now create the links
		int linkIndex = 0;
		for (SubstrateLink link : substrate.getLinks()) {
			SubstrateNode source = link.getSource();
			SubstrateNode target = link.getTarget();
			MLData input = new BasicMLData(cppn.getInputCount());
			int index = 0;
			for (double d : source.getLocation()) {
				input.setData(index++, d);
			}
			for (double d : target.getLocation()) {
				input.setData(index++, d);
			}
			MLData output = cppn.compute(input);
			
			double weight = output.getData(0);
			if(Math.abs(weight)>this.minWeight) {
				weight = (Math.abs(weight) - this.minWeight) * c * Math.signum(weight);
				linkList.add(new NEATLink(source.getId(), target.getId(),weight));
			}
			
			double biasWeight = output.getData(1);
			if( Math.abs(biasWeight)>this.minWeight) {
				biasWeight = (Math.abs(biasWeight) - this.minWeight) * c * Math.signum(biasWeight);
				linkList.add( new NEATLink(0, target.getId(), biasWeight));
			}
		}
	
		Collections.sort(linkList);

		NEATNetwork network = new NEATNetwork(substrate.getInputCount(),
				substrate.getOutputCount(), linkList, afs);

		network.setActivationCycles(pop.getActivationCycles());
		return network;

	}

	@Override
	public Genome encode(MLMethod phenotype) {
		throw new GeneticError(
				"Encoding of a HyperNEAT network is not supported.");
	}

	/**
	 * @return the minWeight
	 */
	public double getMinWeight() {
		return minWeight;
	}

	/**
	 * @param minWeight the minWeight to set
	 */
	public void setMinWeight(double minWeight) {
		this.minWeight = minWeight;
	}

	/**
	 * @return the maxWeight
	 */
	public double getMaxWeight() {
		return maxWeight;
	}

	/**
	 * @param maxWeight the maxWeight to set
	 */
	public void setMaxWeight(double maxWeight) {
		this.maxWeight = maxWeight;
	}
	
	

}

@@ -65,34 +65,8 @@
 t;%0D%0A
-import java.util.Arrays;%0D%0A
 impo
@@ -966,28 +966,16 @@
 .0;%0D%0A%09%0D%0A
-%09@Override%0D%0A
 %09public 
@@ -990,16 +990,57 @@
  decode(
+NEATPopulation pop, Substrate substrate, 
 Genome g
@@ -1181,147 +1181,8 @@
 %0D%0A%0D%0A
-%09%09// create the phenotype%0D%0A%09%09NEATPopulation pop = (NEATPopulation) genome.getPopulation();%0D%0A%09%09Substrate substrate = pop.getSubstrate();%0D%0A%0D%0A
 %09%09Li
@@ -2763,16 +2763,231 @@
 twork;%0D%0A
+%09%09%0D%0A%09%7D%0D%0A%09%0D%0A%09@Override%0D%0A%09public MLMethod decode(Genome genome) %7B%0D%0A%09%09NEATPopulation pop = (NEATPopulation) genome.getPopulation();%0D%0A%09%09Substrate substrate = pop.getSubstrate();%0D%0A%09%09return decode(pop, substrate, genome);
 %0D%0A%09%7D%0D%0A%0D%0A

Allow rez in HyperNEAT to change