aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend/statistics
diff options
context:
space:
mode:
Diffstat (limited to 'src/jcgp/backend/statistics')
-rw-r--r--src/jcgp/backend/statistics/RunEntry.java62
-rw-r--r--src/jcgp/backend/statistics/StatisticsLogger.java233
2 files changed, 295 insertions, 0 deletions
diff --git a/src/jcgp/backend/statistics/RunEntry.java b/src/jcgp/backend/statistics/RunEntry.java
new file mode 100644
index 0000000..0953c49
--- /dev/null
+++ b/src/jcgp/backend/statistics/RunEntry.java
@@ -0,0 +1,62 @@
+package jcgp.backend.statistics;
+
+/**
+ * This class encapsulates the data contained in a log entry.
+ * <br><br>
+ * Once constructed, data can only be retrieved. Note that
+ * the generation argument in the constructor (and consequently
+ * the value returned by {@code getGeneration()} refer to the
+ * last generation when improvement occurred.
+ *
+ * @see StatisticsLogger
+ * @author Eduardo Pedroni
+ *
+ */
+public class RunEntry {
+
+ private int generation, activeNodes;
+ private double bestFitness;
+ private boolean successful;
+
+ /**
+ * Creates a new run entry for a logger.
+ *
+ * @param generation the generation when fitness improvement last occurred.
+ * @param fitness the best fitness achieved.
+ * @param active the number of active nodes in the best solution found.
+ * @param successful whether or not the run found a perfect solution.
+ */
+ public RunEntry(int generation, double fitness, int active, boolean successful) {
+ this.generation = generation;
+ this.bestFitness = fitness;
+ this.activeNodes = active;
+ this.successful = successful;
+ }
+
+ /**
+ * @return the generation when improvement last occurred.
+ */
+ public int getGeneration() {
+ return generation;
+ }
+ /**
+ * @return the best fitness achieved during the run.
+ */
+ public double getFitness() {
+ return bestFitness;
+ }
+ /**
+ * @return true if the run was successful.
+ */
+ public boolean isSuccessful() {
+ return successful;
+ }
+
+ /**
+ * @return the number of active nodes in the best solution found.
+ */
+ public int getActiveNodes() {
+ return activeNodes;
+ }
+
+}
diff --git a/src/jcgp/backend/statistics/StatisticsLogger.java b/src/jcgp/backend/statistics/StatisticsLogger.java
new file mode 100644
index 0000000..dfbcdbe
--- /dev/null
+++ b/src/jcgp/backend/statistics/StatisticsLogger.java
@@ -0,0 +1,233 @@
+package jcgp.backend.statistics;
+
+import java.util.ArrayList;
+
+/**
+ * This is a utility class for logging experiment statistics when doing multiple runs.
+ * <br><br>
+ * Information about each run is added via the {@code logRun()} method. The many getters
+ * can be used to obtain statistics about the logged runs, such as success rate and average
+ * fitness.
+ * <br><br>
+ * {@code JCGP} uses this class to perform its logging and print out experiment data at the end.
+ *
+ *
+ * @author Eduardo Pedroni
+ *
+ */
+public class StatisticsLogger {
+
+ // this list holds the logged entries
+ private ArrayList<RunEntry> runEntries;
+
+ /**
+ * Create a new statistics logger, use this when resetting is necessary.
+ */
+ public StatisticsLogger() {
+ runEntries = new ArrayList<RunEntry>();
+ }
+
+ /**
+ * Log a new run. Calling any of the statistics getters will
+ * now take this logged run into account as well as all previously
+ * logged runs.
+ *
+ * @param generation the last generation when improvement occurred.
+ * @param fitness the best fitness achieved in the run.
+ * @param active the number of active nodes in the best chromosome found.
+ * @param successful true if a perfect solution was found, false if otherwise.
+ */
+ public void logRun(int generation, double fitness, int active, boolean successful) {
+ runEntries.add(new RunEntry(generation, fitness, active, successful));
+ }
+
+ /**
+ * Averages the best fitness obtained in each run.
+ *
+ * @return the average fitness.
+ */
+ public double getAverageFitness() {
+ double average = 0;
+ for (RunEntry runEntry : runEntries) {
+ average += runEntry.getFitness() / runEntries.size();
+ }
+ return average;
+ }
+
+ /**
+ * Calculates the standard deviation of
+ * the best fitness obtained in each run.
+ *
+ * @return the standard deviation of average fitnesses.
+ */
+ public double getAverageFitnessStdDev() {
+ double average = getAverageFitness();
+ double temp, stdDev = 0;
+ for (RunEntry runEntry : runEntries) {
+ temp = runEntry.getFitness() - average;
+ temp = temp * temp;
+ stdDev += temp;
+ }
+ return stdDev;
+ }
+
+ /**
+ * Averages the number of active nodes in the
+ * best chromosomes obtained across all runs.
+ *
+ * @return the average number of active nodes.
+ */
+ public double getAverageActiveNodes() {
+ double average = 0;
+ for (RunEntry runEntry : runEntries) {
+ average += runEntry.getActiveNodes() / runEntries.size();
+ }
+ return average;
+ }
+
+ /**
+ * Calculates the standard deviation of
+ * the number of active nodes in the best solution
+ * in each run.
+ *
+ * @return the standard deviation of active node counts.
+ */
+ public double getAverageActiveNodesStdDev() {
+ double average = getAverageActiveNodes();
+ double temp, stdDev = 0;
+ for (RunEntry runEntry : runEntries) {
+ temp = runEntry.getActiveNodes() - average;
+ temp = temp * temp;
+ stdDev += temp;
+ }
+ return stdDev;
+ }
+
+ /**
+ * Calculates the average generation out of all runs.
+ * The generation value in each run corresponds to the
+ * last generation in which improvement happened.
+ * <br><br>
+ * Note that this method includes runs where no perfect
+ * solution was found. For the average number of generations
+ * for perfect solutions only, use {@code getAverageSuccessfulGenerations}.
+ *
+ * @return the average number of generations.
+ */
+ public double getAverageGenerations() {
+ double average = 0;
+ for (RunEntry runEntry : runEntries) {
+ average += runEntry.getGeneration() / runEntries.size();
+ }
+ return average;
+ }
+
+ /**
+ * Calculates the standard deviation of
+ * the average number of generations in
+ * each run.
+ *
+ * @return the standard deviation of the number of generations.
+ */
+ public double getAverageGenerationsStdDev() {
+ double average = getAverageGenerations();
+ double temp, stdDev = 0;
+ for (RunEntry runEntry : runEntries) {
+ temp = runEntry.getGeneration() - average;
+ temp = temp * temp;
+ stdDev += temp;
+ }
+ return stdDev;
+ }
+
+ /**
+ * @return the highest fitness across all runs.
+ */
+ public double getHighestFitness() {
+ double highest = 0;
+ for (RunEntry runEntry : runEntries) {
+ if (runEntry.getFitness() > highest) {
+ highest = runEntry.getFitness();
+ }
+ }
+ return highest;
+ }
+
+ /**
+ * @return the lowest fitness across all runs.
+ */
+ public double getLowestFitness() {
+ double lowest = Double.MAX_VALUE;
+ for (RunEntry runEntry : runEntries) {
+ if (runEntry.getFitness() < lowest) {
+ lowest = runEntry.getFitness();
+ }
+ }
+ return lowest;
+ }
+
+ /**
+ *
+ * @return the number of runs in which a perfect solution was found.
+ */
+ public int getSuccessfulRuns() {
+ int count = 0;
+ for (RunEntry runEntry : runEntries) {
+ if (runEntry.isSuccessful()) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Calculates the ratio of successful runs (runs where
+ * a perfect solution was found) to total number of runs.
+ * A double-precision value between 0 and 1 is returned,
+ * where 0 means 0% success rate and 1 means 100% success rate.
+ *
+ * @return the success rate across all runs.
+ */
+ public double getSuccessRate() {
+ return getSuccessfulRuns() / runEntries.size();
+ }
+
+ /**
+ * Calculates the average generation out of successful runs only.
+ * The generation value in each successful run corresponds to the
+ * generation in which the perfect solution was found.
+ *
+ * @return the average number of generations for perfect solutions.
+ */
+ public double getAverageSuccessfulGenerations() {
+ double average = 0;
+ int successfulRuns = getSuccessfulRuns();
+ for (RunEntry runEntry : runEntries) {
+ if (runEntry.isSuccessful()) {
+ average += runEntry.getGeneration() / successfulRuns;
+ }
+ }
+ return average;
+ }
+
+ /**
+ * Calculates the standard deviation of
+ * the average number of generations in
+ * each run where a perfect solution was found.
+ *
+ * @return the standard deviation of the number of generations in successful runs.
+ */
+ public double getAverageSuccessfulGenerationsStdDev() {
+ double average = getAverageSuccessfulGenerations();
+ double temp, stdDev = 0;
+ for (RunEntry runEntry : runEntries) {
+ if (runEntry.isSuccessful()) {
+ temp = runEntry.getGeneration() - average;
+ temp = temp * temp;
+ stdDev += temp;
+ }
+ }
+ return stdDev;
+ }
+
+}