gt: 			Set<Long> connectedInputs = new HashSet<>();
context: /*
   * Copyright (C) 2004 Derek James and Philip Tucker
   * 
   * This file is part of ANJI (Another NEAT Java Implementation).
   * 
   * ANJI is free software; you can redistribute it and/or modify it under the terms of the GNU
   * General Public License as published by the Free Software Foundation; either version 2 of the
   * License, or (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
   * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
   * the GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public License along with this program; if
   * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   * 02111-1307 USA
   * 
   * created by Philip Tucker on Feb 16, 2003
   */
  package mil.af.rl.anji.learner;
  
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Calendar;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.LinkedHashMap;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.SortedSet;
  import java.util.TreeSet;
  
  import mil.af.rl.anji.NeatChromosomeUtility;
  import mil.af.rl.anji.NeatConfigurationAdapter;
  import mil.af.rl.predictive.EagerChromosomeSampleContainer;
  import mil.af.rl.predictive.PFSInfo;
  import mil.af.rl.predictive.PredictiveLearner;
  import mil.af.rl.predictive.SampleContainer;
  import mil.af.rl.predictive.SubspaceIdentification;
  
  import org.apache.log4j.Logger;
  import org.jgap.Allele;
  import org.jgap.BulkFitnessFunction;
  import org.jgap.Chromosome;
  import org.jgap.ChromosomeMaterial;
  import org.jgap.Genotype;
  import org.jgap.GenotypeAdapter;
  import org.jgap.event.GeneticEvent;
  
  import com.anji.integration.LogEventListener;
  import com.anji.integration.PersistenceEventListener;
  import com.anji.neat.ConnectionAllele;
  import com.anji.neat.NeatConfiguration;
  import com.anji.neat.NeuronAllele;
  import com.anji.neat.NeuronType;
  import com.anji.persistence.Persistence;
  import com.anji.run.Run;
  import com.anji.util.Configurable;
  import com.anji.util.Properties;
  import com.anji.util.Reset;
  
  /**
   * Configures and performs an ANJI evolutionary run.
   * 
   * @author Philip Tucker
   * @author Steven Loscalzo modified for compatibility with PFS.
   */
  public class Evolver implements Configurable, PredictiveLearner {
  	
  	private static Logger logger = Logger.getLogger(Evolver.class);
  
  	//These are all keys for properties file info
  	/** properties key, # generations in run */
  	public static final String NUM_GENERATIONS_KEY = "num.generations";
  	/** properties key, fitness function class */
  	public static final String FITNESS_FUNCTION_CLASS_KEY = "fitness_function";
  	/** whether or not the genotype should be read from an existing source */
  	public static final String RESET_KEY = "run.reset";
  	/** properties key, target fitness value - after reaching this run will halt */
  	public static final String FITNESS_TARGET_KEY = "fitness.target";
  	/** the size of the number of inputs to the networks (at maximum) */
  	public static final String NUM_FEATURES = "stimulus.size";
  	
  	//State variables for this class
  	/** The configuration file */
  	private NeatConfiguration config = null;
  	/** Champion chromosome */
  	private Chromosome champ = null;
  	/** The Genotype that is being evolved */
  	private GenotypeAdapter genotype = null;
  	/** The maximum number of evolutions to allow */
  	private int numEvolutions = 0;
  	private double targetFitness = 0.0;
  	private double thresholdFitness = 0.0;
  	private int maxFitness = 0;
  	private Persistence db = null;
  	private Date runStartDate;
  	private DateFormat fmt;
  	private int generationOfFirstSolution;
  	private double adjustedFitness;
  	private int generation = 0;
  
  	//PFS specific information:
  	/** The storage container used to keep track of samples */
  	private SampleContainer container;
  	/** Whether or not to collect samples (optimization) */
  	private boolean collect = false;
  	/** The current set of selected features, mapped to the number when it was
  	 * selected, or -1 (SubspaceIdentification.UNUSED) if it is not currently
  	 * selected. */
  	private Map<Integer, Integer> selectedFeatures;
  	/** The previous set of selected features, used to roll-back if necessary */
  	private Map<Integer, Integer> reversionSelectedFeatures;
  	/** An example chromosome in the roll-back generation */
  	private Chromosome reversionBest;
  	/** The current run */
  	private Run run;
  	/** The shared PFS info object - could be a singleton pattern. */
  	private PFSInfo info = new PFSInfo();
  	/** Fitness function to use during evaluation */
  	private BulkFitnessFunction fitnessFunc;
  	/** The number of chromosomes to sample with lazy sampling (better on mem, worse on time) 
  	 * This is only used if EagerChromosomeSampleContainer is not used. */
  	private int lazyK = 5;
  	/**
  	 * ctor; must call <code>init()</code> before using this object
  	 */
  	public Evolver() {
  		super();
  	}
  
  	/**
  	 * Construct new evolver with given properties. See <a href=" {@docRoot}
  	 * /params.htm" target="anji_params">Parameter Details </a> for specific
  	 * property settings.
  	 * 
  	 * @see com.anji.util.Configurable#init(com.anji.util.Properties)
  	 */
  	public void init(Properties props) throws Exception {
  		boolean doReset = props.getBooleanProperty(RESET_KEY, false);
  		if (doReset) {
  			logger.warn("Resetting previous run !!!");
  			Reset resetter = new Reset(props);
  			resetter.setUserInteraction(false);
  			resetter.reset();
  		}
  
  		config = new NeatConfigurationAdapter(props);
  
  		// peristence
  		db = (Persistence) props
  				.singletonObjectProperty(Persistence.PERSISTENCE_CLASS_KEY);
  		//Ending criteria
  		numEvolutions = props.getIntProperty(NUM_GENERATIONS_KEY);
  		targetFitness = props.getDoubleProperty(FITNESS_TARGET_KEY, 1.0d);
  		thresholdFitness = props.getDoubleProperty(ConcurrentFitnessFunction.THRESHOLD_KEY,
  				targetFitness);
  
  		run = (Run) props.singletonObjectProperty(Run.class);
  		db.startRun(run.getName());
  		// fitness function
  		fitnessFunc = (BulkFitnessFunction) props
  				.newObjectProperty(FITNESS_FUNCTION_CLASS_KEY);
  		//Make sure the same object is used throughout
  		((ConcurrentFitnessFunction)fitnessFunc).setPFSInfo(info);
  		
  		config.getEventManager().addEventListener(
  				GeneticEvent.GENOTYPE_EVALUATED_EVENT, run);
  
  		// logging
  		LogEventListener logListener = new LogEventListener(config);
  		config.getEventManager().addEventListener(
  				GeneticEvent.GENOTYPE_EVOLVED_EVENT, logListener);
  		config.getEventManager().addEventListener(
  				GeneticEvent.GENOTYPE_EVALUATED_EVENT, logListener);
  
  		// persistence
  		PersistenceEventListener dbListener = new PersistenceEventListener(
  				config, run);
  		dbListener.init(props);
  		config.getEventManager()
  		.addEventListener(
  				GeneticEvent.GENOTYPE_START_GENETIC_OPERATORS_EVENT,
  				dbListener);
  		config.getEventManager().addEventListener(
  				GeneticEvent.GENOTYPE_FINISH_GENETIC_OPERATORS_EVENT,
  				dbListener);
  		config.getEventManager().addEventListener(
  				GeneticEvent.GENOTYPE_EVALUATED_EVENT, dbListener);
  		config.setBulkFitnessFunction(fitnessFunc);
  
  		maxFitness = config.getBulkFitnessFunction().getMaxFitnessValue();
  
  		// load population, either from previous run or random
  		Genotype geno = db.loadGenotype(config);
  		int numFeatures = props.getIntProperty(NUM_FEATURES);
  		// At first we have the identity mapping
  		selectedFeatures = new LinkedHashMap<Integer, Integer>();
  		for (int i = 0; i < numFeatures; ++i)
  			selectedFeatures.put(i, i);
  		
  		if (geno != null) {
  			genotype = new GenotypeAdapter(geno, info);
  			logger.info("genotype from previous run");
  			// See if we need to assign a selected feature subset
  			Chromosome c = genotype.getFittestChromosome();
  			// Get the champion's selected set
  			//Determine all the input nodes and if they're connected:
  			@SuppressWarnings("unchecked")
  			SortedSet<Allele> allAlleles = c.getAlleles();
  			List<NeuronAllele> inputs = NeatChromosomeUtility.getNeuronList(allAlleles, NeuronType.INPUT);
  			//Align the order with how the problem expects them
  			Collections.sort(inputs, new InputNeuronComparator());
  			//Now figure out which connections link up to these nodes
  			List<ConnectionAllele> conns = NeatChromosomeUtility.getConnectionList(allAlleles);
  