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 }