/// <summary> /// Evaluates the program versus each set of training inputs and /// computes the custom fitness of the program. /// </summary> /// <param name="ProgramID">Index of the program in the Population</param> /// <param name="Predictions">Set of predicted values by the program</param> /// <returns>Custom fitness of the program</returns> private double ComputeProgramFitness(int ProgramID, double[] Predictions) { GPProgram Program = m_Population.Programs[ProgramID]; // // Start by converting the program into a tree representation Program.ConvertToTree(m_Config.FunctionSet, true); // // Set the memory size Program.CountMemory = m_Config.Profile.CountMemory; // // Test each item in the training data set m_FitnessHits[ProgramID] = 0; for (int FitnessTest = 0; FitnessTest < m_TrainingData.Rows && !m_Abort; FitnessTest++) { // // Assign the input values to the program Program.UserTerminals = m_TrainingData.InputRow(FitnessTest); // // Assign a reference to the historical set of data for this fitness test if (m_UseInputHistory) { Program.InputHistory = m_UserInputHistory[FitnessTest]; } // // This is the money shot, execute the genetic program! double Result = Program.EvaluateAsDouble(); // // Deal with problems that might have come up during the fitness computation if (double.IsInfinity(Result) || double.IsNaN(Result) || double.IsNegativeInfinity(Result) || double.IsPositiveInfinity(Result)) { Result = m_MaximumError; } // // If the program size is above our threshold size, give it the // worst possible result to prevent it from being used in any of the // genetic operations. There is a problem if the number of nodes in // the tree gets about the size of a 'short', we loose the ability to // count and label them. Question...why not use an 'int'? Two reasons... // 1. A program bigger than 16bits of nodes is ridiculous in the first place // 2. Memory, each node would require 32bits for a lable, instead of 16bits, // it doubles that bit of storage, which we don't need. if (Program.CountNodes >= GPEnums.PROGRAMSIZE_THRESHOLD) { Result = m_MaximumError; } // // Store the Program result Predictions[FitnessTest] = Result; // // Determine if we have a "hit" against the input data double Error = Math.Abs(Result - m_TrainingData.ObjectiveRow(FitnessTest)[0]); if (Error <= m_Tolerance && Error >= -m_Tolerance) { m_FitnessHits[ProgramID]++; } } // // Restore it back to an array. Program.ConvertToArray(m_Config.FunctionSet); // // Make a call into the custom fitness object to evaluate the // fitness of the program. double ProgramFitness = m_Config.Fitness.ComputeFitness( m_UserInputHistoryCustomFitness, Predictions, m_TrainingData.ObjectiveColumn(0), m_TrainingAverage, m_Tolerance); // // Still have to check the result for problems if (double.IsNaN(ProgramFitness) || double.IsInfinity(ProgramFitness) || double.IsPositiveInfinity(ProgramFitness) || double.IsNegativeInfinity(ProgramFitness)) { ProgramFitness = m_FitnessMeasure[m_WorstProgramGeneration]; } return(ProgramFitness); }
public double[] InputRow(int Row) { return(m_Training.InputRow(Row)); }