github.com/yaricom/goNEAT@v0.0.0-20210507221059-e2110b885482/experiments/trial.go (about)

     1  package experiments
     2  
     3  import (
     4  	"time"
     5  	"github.com/yaricom/goNEAT/neat/genetics"
     6  	"sort"
     7  	"encoding/gob"
     8  )
     9  
    10  // The structure to hold statistics about one experiment run (trial)
    11  type Trial struct {
    12  	// The trial number
    13  	Id               int
    14  	// The results per generation in this trial
    15  	Generations      Generations
    16  	// The winner generation
    17  	WinnerGeneration *Generation
    18  
    19  	// The elapsed time between trial start and finish
    20  	Duration         time.Duration
    21  }
    22  
    23  // Calculates average duration of evaluations among all generations of organism populations in this trial
    24  func (t *Trial) AvgEpochDuration() time.Duration {
    25  	total := time.Duration(0)
    26  	for _, i := range t.Generations {
    27  		total += i.Duration
    28  	}
    29  	return total / time.Duration(len(t.Generations))
    30  }
    31  
    32  func (t *Trial) LastExecuted() time.Time {
    33  	var u time.Time
    34  	for _, i := range t.Generations {
    35  		if u.Before(i.Executed) {
    36  			u = i.Executed
    37  		}
    38  	}
    39  	return u
    40  }
    41  
    42  // Finds the most fit organism among all epochs in this trial. It's also possible to get the best organism only among the ones
    43  // which was able to solve the experiment's problem.
    44  func (t *Trial) BestOrganism(onlySolvers bool) (*genetics.Organism, bool) {
    45  	var orgs = make(genetics.Organisms, 0, len(t.Generations))
    46  	for _, e := range t.Generations {
    47  		if !onlySolvers {
    48  			// include all the most fit in each epoch
    49  			orgs = append(orgs, e.Best)
    50  		} else if e.Solved {
    51  			// include only task solvers
    52  			orgs = append(orgs, e.Best)
    53  		}
    54  	}
    55  	if len(orgs) > 0 {
    56  		sort.Sort(sort.Reverse(orgs))
    57  		return orgs[0], true
    58  	} else {
    59  		return nil, false
    60  	}
    61  }
    62  
    63  func (t *Trial) Solved() bool {
    64  	for _, e := range t.Generations {
    65  		if e.Solved {
    66  			return true
    67  		}
    68  	}
    69  	return false
    70  }
    71  
    72  // Fitness returns the fitnesses of the best organisms for each epoch in this trial
    73  func (t *Trial) BestFitness() Floats {
    74  	var x Floats = make([]float64, len(t.Generations))
    75  	for i, e := range t.Generations {
    76  		x[i] = e.Best.Fitness
    77  
    78  	}
    79  	return x
    80  }
    81  
    82  // Age returns the age of the best species for each epoch in this trial
    83  func (t *Trial) BestAge() Floats {
    84  	var x Floats = make([]float64, len(t.Generations))
    85  	for i, e := range t.Generations {
    86  		x[i] = float64(e.Best.Species.Age)
    87  	}
    88  	return x
    89  }
    90  
    91  // Complexity returns the complexity of the best species for each epoch in this trial
    92  func (t *Trial) BestComplexity() Floats {
    93  	var x Floats = make([]float64, len(t.Generations))
    94  	for i, e := range t.Generations {
    95  		x[i] = float64(e.Best.Phenotype.Complexity())
    96  	}
    97  	return x
    98  }
    99  
   100  
   101  // Diversity returns number of species for each epoch
   102  func (t *Trial) Diversity() Floats {
   103  	var x Floats = make([]float64, len(t.Generations))
   104  	for i, e := range t.Generations {
   105  		x[i] = float64(e.Diversity)
   106  	}
   107  	return x
   108  }
   109  
   110  // Returns average fitness, age, and complexity of population of organisms for each epoch in this trial
   111  func (t *Trial) Average() (fitness, age, complexity Floats) {
   112  	fitness = make(Floats, len(t.Generations))
   113  	age = make(Floats, len(t.Generations))
   114  	complexity = make(Floats, len(t.Generations))
   115  	for i, e := range t.Generations {
   116  		fitness[i], age[i], complexity[i] = e.Average()
   117  	}
   118  	return fitness, age, complexity
   119  }
   120  
   121  // Returns number of nodes, genes,  organism evaluations and species diversity in the winner genome
   122  func (t *Trial) Winner() (nodes, genes, evals, diversity int) {
   123  	if t.WinnerGeneration != nil {
   124  		nodes = t.WinnerGeneration.WinnerNodes
   125  		genes = t.WinnerGeneration.WinnerGenes
   126  		evals = t.WinnerGeneration.WinnerEvals
   127  		diversity = t.WinnerGeneration.Diversity
   128  	} else {
   129  		for _, e := range t.Generations {
   130  			if e.Solved {
   131  				nodes = e.WinnerNodes
   132  				genes = e.WinnerGenes
   133  				evals = e.WinnerEvals
   134  				diversity = e.Diversity
   135  				// Store winner
   136  				t.WinnerGeneration = &e
   137  				break
   138  			}
   139  		}
   140  	}
   141  	return nodes, genes, evals, diversity
   142  }
   143  
   144  // Encodes this trial
   145  func (t *Trial) Encode(enc *gob.Encoder) error {
   146  	err := enc.Encode(t.Id)
   147  	err = enc.Encode(len(t.Generations))
   148  	for _, e := range t.Generations {
   149  		err = e.Encode(enc)
   150  		if err != nil {
   151  			return err
   152  		}
   153  	}
   154  	return err
   155  }
   156  
   157  // Decodes trial data
   158  func (t *Trial) Decode(dec *gob.Decoder) error {
   159  	err := dec.Decode(&t.Id)
   160  	var ngen int
   161  	err = dec.Decode(&ngen)
   162  	if err != nil {
   163  		return err
   164  	}
   165  	t.Generations = make([]Generation, ngen)
   166  	for i := 0; i < ngen; i++ {
   167  		gen := Generation{}
   168  		err = gen.Decode(dec)
   169  		if err != nil {
   170  			return err
   171  		}
   172  		t.Generations[i] = gen
   173  	}
   174  	return err
   175  }
   176  
   177  // Trials is a sortable collection of experiment runs (trials) by execution time and id
   178  type Trials []Trial
   179  
   180  func (ts Trials) Len() int {
   181  	return len(ts)
   182  }
   183  func (ts Trials) Swap(i, j int) {
   184  	ts[i], ts[j] = ts[j], ts[i]
   185  }
   186  func (ts Trials) Less(i, j int) bool {
   187  	ui := ts[i].LastExecuted()
   188  	uj := ts[j].LastExecuted()
   189  	if ui.Equal(uj) {
   190  		return ts[i].Id < ts[j].Id
   191  	}
   192  	return ui.Before(uj)
   193  }