github.com/yaricom/goNEAT@v0.0.0-20210507221059-e2110b885482/experiments/generation.go (about) 1 package experiments 2 3 import ( 4 "time" 5 "github.com/yaricom/goNEAT/neat/genetics" 6 "math" 7 "encoding/gob" 8 "bytes" 9 "reflect" 10 "sort" 11 ) 12 13 // The structure to represent execution results of one generation 14 type Generation struct { 15 // The generation ID for this epoch 16 Id int 17 // The time when epoch was evaluated 18 Executed time.Time 19 // The elapsed time between generation execution start and finish 20 Duration time.Duration 21 // The best organism of best species 22 Best *genetics.Organism 23 // The flag to indicate whether experiment was solved in this epoch 24 Solved bool 25 26 // The list of organisms fitness values per species in population 27 Fitness Floats 28 // The age of organisms per species in population 29 Age Floats 30 // The list of organisms complexities per species in population 31 Compexity Floats 32 33 // The number of species in population at the end of this epoch 34 Diversity int 35 36 // The number of evaluations done before winner found 37 WinnerEvals int 38 // The number of nodes in winner genome or zero if not solved 39 WinnerNodes int 40 // The numbers of genes (links) in winner genome or zero if not solved 41 WinnerGenes int 42 43 // The ID of Trial this Generation was evaluated in 44 TrialId int 45 } 46 47 // Collects statistics about given population 48 func (epoch *Generation) FillPopulationStatistics(pop *genetics.Population) { 49 max_fitness := float64(math.MinInt64) 50 epoch.Diversity = len(pop.Species) 51 epoch.Age = make(Floats, epoch.Diversity) 52 epoch.Compexity = make(Floats, epoch.Diversity) 53 epoch.Fitness = make(Floats, epoch.Diversity) 54 for i, curr_species := range pop.Species { 55 epoch.Age[i] = float64(curr_species.Age) 56 epoch.Compexity[i] = float64(curr_species.Organisms[0].Phenotype.Complexity()) 57 epoch.Fitness[i] = curr_species.Organisms[0].Fitness 58 59 // find best organism in epoch if not solved 60 if !epoch.Solved { 61 // sort organisms from current species by fitness to have most fit first 62 sort.Sort(sort.Reverse(curr_species.Organisms)) 63 if curr_species.Organisms[0].Fitness > max_fitness { 64 max_fitness = curr_species.Organisms[0].Fitness 65 epoch.Best = curr_species.Organisms[0] 66 } 67 } 68 } 69 } 70 71 // Returns average fitness, age, and complexity among all organisms from population at the end of this epoch 72 func (epoch *Generation) Average() (fitness, age, complexity float64) { 73 fitness = epoch.Fitness.Mean() 74 age = epoch.Age.Mean() 75 complexity = epoch.Compexity.Mean() 76 return fitness, age, complexity 77 } 78 79 // Encodes generation with provided GOB encoder 80 func (epoch *Generation) Encode(enc *gob.Encoder) error { 81 err := enc.EncodeValue(reflect.ValueOf(epoch.Id)) 82 err = enc.EncodeValue(reflect.ValueOf(epoch.Executed)) 83 err = enc.EncodeValue(reflect.ValueOf(epoch.Solved)) 84 err = enc.EncodeValue(reflect.ValueOf(epoch.Fitness)) 85 err = enc.EncodeValue(reflect.ValueOf(epoch.Age)) 86 err = enc.EncodeValue(reflect.ValueOf(epoch.Compexity)) 87 err = enc.EncodeValue(reflect.ValueOf(epoch.Diversity)) 88 err = enc.EncodeValue(reflect.ValueOf(epoch.WinnerEvals)) 89 err = enc.EncodeValue(reflect.ValueOf(epoch.WinnerNodes)) 90 err = enc.EncodeValue(reflect.ValueOf(epoch.WinnerGenes)) 91 92 if err != nil { 93 return err 94 } 95 96 // encode best organism 97 if epoch.Best != nil { 98 err = encodeOrganism(enc, epoch.Best) 99 } 100 return err 101 } 102 103 func encodeOrganism(enc *gob.Encoder, org *genetics.Organism) error { 104 err := enc.Encode(org.Fitness) 105 err = enc.Encode(org.IsWinner) 106 err = enc.Encode(org.Generation) 107 err = enc.Encode(org.ExpectedOffspring) 108 err = enc.Encode(org.Error) 109 110 if err != nil { 111 return err 112 } 113 114 // encode organism genome 115 if org.Genotype != nil { 116 err = enc.Encode(org.Genotype.Id) 117 out_buf := bytes.NewBufferString("") 118 org.Genotype.Write(out_buf) 119 err = enc.Encode(out_buf.Bytes()) 120 } 121 122 return err 123 } 124 125 func (epoch *Generation) Decode(dec *gob.Decoder) error { 126 err := dec.Decode(&epoch.Id) 127 err = dec.Decode(&epoch.Executed) 128 err = dec.Decode(&epoch.Solved) 129 err = dec.Decode(&epoch.Fitness) 130 err = dec.Decode(&epoch.Age) 131 err = dec.Decode(&epoch.Compexity) 132 err = dec.Decode(&epoch.Diversity) 133 err = dec.Decode(&epoch.WinnerEvals) 134 err = dec.Decode(&epoch.WinnerNodes) 135 err = dec.Decode(&epoch.WinnerGenes) 136 137 if err != nil { 138 return err 139 } 140 141 // decode organism 142 org, err := decodeOrganism(dec) 143 if err == nil { 144 epoch.Best = org 145 } 146 return err 147 } 148 149 func decodeOrganism(dec *gob.Decoder) (*genetics.Organism, error) { 150 org := genetics.Organism{} 151 err := dec.Decode(&org.Fitness) 152 err = dec.Decode(&org.IsWinner) 153 err = dec.Decode(&org.Generation) 154 err = dec.Decode(&org.ExpectedOffspring) 155 err = dec.Decode(&org.Error) 156 157 if err != nil { 158 return nil, err 159 } 160 161 // decode organism genome 162 var gen_id int 163 err = dec.Decode(&gen_id) 164 var data []byte 165 err = dec.Decode(&data) 166 gen, err := genetics.ReadGenome(bytes.NewBuffer(data), gen_id) 167 org.Genotype = gen 168 169 return &org, err 170 } 171 172 // Generations is a sortable collection of generations by execution time and Id 173 type Generations []Generation 174 175 func (is Generations) Len() int { 176 return len(is) 177 } 178 func (is Generations) Swap(i, j int) { 179 is[i], is[j] = is[j], is[i] 180 } 181 func (is Generations) Less(i, j int) bool { 182 if is[i].Executed.Equal(is[j].Executed) { 183 return is[i].Id < is[j].Id // less is from earlier epochs 184 } 185 return is[i].Executed.Before(is[j].Executed) // less is from earlier time 186 }