github.com/yaricom/goNEAT@v0.0.0-20210507221059-e2110b885482/neat/genetics/organism.go (about)

     1  package genetics
     2  
     3  import (
     4  	"github.com/yaricom/goNEAT/neat/network"
     5  	"fmt"
     6  	"bytes"
     7  )
     8  
     9  // The object to associate implementation specific data with particular organism for various algorithm implementations
    10  type OrganismData struct {
    11  	// The implementation specific data object to be associated with organism
    12  	Value interface{}
    13  }
    14  
    15  // Organisms are Genotypes (Genomes) and Phenotypes (Networks) with fitness information,
    16  // i.e. the genotype and phenotype together.
    17  type Organism struct {
    18  	// A measure of fitness for the Organism
    19  	Fitness                   float64
    20  	// The error value indicating how far organism's performance is from ideal task goal, e.g. MSE
    21  	Error                     float64
    22  	// Win marker (if needed for a particular task)
    23  	IsWinner                  bool
    24  
    25  	// The Organism's phenotype
    26  	Phenotype                 *network.Network
    27  	// The Organism's genotype
    28  	Genotype                  *Genome
    29  	// The Species of the Organism
    30  	Species                   *Species
    31  
    32  	// Number of children this Organism may have
    33  	ExpectedOffspring         float64
    34  	// Tells which generation this Organism is from
    35  	Generation                int
    36  
    37  	// The utility data transfer object to be used by different GA implementations to hold additional data.
    38  	// Implemented as ANY to allow implementation specific objects.
    39  	Data                      *OrganismData
    40  
    41  	// A fitness measure that won't change during fitness adjustments of population's epoch evaluation
    42  	originalFitness           float64
    43  
    44  	// Marker for destruction of inferior Organisms
    45  	toEliminate               bool
    46  	// Marks the species champion
    47  	isChampion                bool
    48  
    49  	// Number of reserved offspring for a population leader
    50  	superChampOffspring       int
    51  	// Marks the best in population
    52  	isPopulationChampion      bool
    53  	// Marks the duplicate child of a champion (for tracking purposes)
    54  	isPopulationChampionChild bool
    55  
    56  	// DEBUG variable - highest fitness of champ
    57  	highestFitness            float64
    58  
    59  	// Track its origin - for debugging or analysis - we can tell how the organism was born
    60  	mutationStructBaby        bool
    61  	mateBaby                  bool
    62  
    63  	// The flag to be used as utility value
    64  	Flag                      int
    65  }
    66  
    67  // Creates new organism with specified genome, fitness and given generation number
    68  func NewOrganism(fit float64, g *Genome, generation int) (org *Organism, err error) {
    69  	phenotype := g.Phenotype
    70  	if phenotype == nil {
    71  		phenotype, err = g.Genesis(g.Id)
    72  		if err != nil {
    73  			return nil, err
    74  		}
    75  	}
    76  	org = &Organism{
    77  		Fitness:fit,
    78  		Genotype:g,
    79  		Phenotype:phenotype,
    80  		Generation:generation,
    81  	}
    82  	return org, nil
    83  }
    84  
    85  // Regenerate the network based on a change in the genotype
    86  func (o *Organism) UpdatePhenotype() (err error) {
    87  	// First, delete the old phenotype (net)
    88  	o.Phenotype = nil
    89  
    90  	// Now, recreate the phenotype off the new genotype
    91  	o.Phenotype, err = o.Genotype.Genesis(o.Genotype.Id)
    92  	return err
    93  }
    94  
    95  // Method to check if this algorithm is champion child and if so than if it's damaged
    96  func (o *Organism) CheckChampionChildDamaged() bool {
    97  	if o.isPopulationChampionChild && o.highestFitness > o.Fitness {
    98  		return true
    99  	}
   100  	return false
   101  }
   102  
   103  // Encodes this organism for wired transmission during parallel reproduction cycle
   104  func (o *Organism) MarshalBinary() ([]byte, error) {
   105  	var buf bytes.Buffer
   106  	_, err := fmt.Fprintln(&buf, o.Fitness, o.Generation, o.highestFitness, o.isPopulationChampionChild, o.Genotype.Id)
   107  	o.Genotype.Write(&buf)
   108  	if err != nil {
   109  		return nil, err
   110  	} else {
   111  		return buf.Bytes(), nil
   112  	}
   113  }
   114  // Decodes organism received over the wire during parallel reproduction cycle
   115  func (o *Organism) UnmarshalBinary(data []byte) error {
   116  	// A simple encoding: plain text.
   117  	b := bytes.NewBuffer(data)
   118  	var genotype_id int
   119  	_, err := fmt.Fscanln(b, &o.Fitness, &o.Generation, &o.highestFitness, &o.isPopulationChampionChild, &genotype_id)
   120  	o.Genotype, err = ReadGenome(b, genotype_id)
   121  	if err == nil {
   122  		o.Phenotype, err = o.Genotype.Genesis(genotype_id)
   123  	}
   124  
   125  	return err
   126  }
   127  
   128  func (o *Organism) String() string {
   129  	champStr := ""
   130  	if o.isChampion {
   131  		champStr = " - CHAMPION - "
   132  	}
   133  	eliminStr := ""
   134  	if o.toEliminate {
   135  		eliminStr = " - TO BE ELIMINATED - "
   136  	}
   137  	return fmt.Sprintf("[Organism generation: %d, fitness: %.3f, original fitness: %.3f%s%s]",
   138  		o.Generation, o.Fitness, o.originalFitness, champStr, eliminStr)
   139  }
   140  
   141  // Dumps all organism's fields into string
   142  func (o *Organism) Dump() string {
   143  	b := bytes.NewBufferString("Organism:")
   144  	fmt.Fprintln(b, "Fitness: ", o.Fitness)
   145  	fmt.Fprintln(b, "Error: ", o.Error)
   146  	fmt.Fprintln(b, "IsWinner: ", o.IsWinner)
   147  	fmt.Fprintln(b, "Phenotype: ", o.Phenotype)
   148  	fmt.Fprintln(b, "Genotype: ", o.Genotype)
   149  	fmt.Fprintln(b, "Species: ", o.Species)
   150  	fmt.Fprintln(b, "ExpectedOffspring: ", o.ExpectedOffspring)
   151  	fmt.Fprintln(b, "Data: ", o.Data)
   152  	fmt.Fprintln(b, "Phenotype: ", o.Phenotype)
   153  	fmt.Fprintln(b, "originalFitness: ", o.originalFitness)
   154  	fmt.Fprintln(b, "toEliminate: ", o.toEliminate)
   155  	fmt.Fprintln(b, "isChampion: ", o.isChampion)
   156  	fmt.Fprintln(b, "superChampOffspring: ", o.superChampOffspring)
   157  	fmt.Fprintln(b, "isPopulationChampion: ", o.isPopulationChampion)
   158  	fmt.Fprintln(b, "isPopulationChampionChild: ", o.isPopulationChampionChild)
   159  	fmt.Fprintln(b, "highestFitness: ", o.highestFitness)
   160  	fmt.Fprintln(b, "mutationStructBaby: ", o.mutationStructBaby)
   161  	fmt.Fprintln(b, "mateBaby: ", o.mateBaby)
   162  	fmt.Fprintln(b, "Flag: ", o.Flag)
   163  
   164  	return b.String()
   165  }
   166  
   167  // Organisms is sortable list of organisms by fitness
   168  type Organisms []*Organism
   169  
   170  func (f Organisms) Len() int {
   171  	return len(f)
   172  }
   173  func (f Organisms) Swap(i, j int) {
   174  	f[i], f[j] = f[j], f[i]
   175  }
   176  func (f Organisms) Less(i, j int) bool {
   177  	if f[i].Fitness < f[j].Fitness {
   178  		// try to promote most fit organisms
   179  		return true  // lower fitness is less
   180  	} else if f[i].Fitness == f[j].Fitness {
   181  		// try to promote less complex organisms
   182  		ci := f[i].Phenotype.Complexity()
   183  		cj := f[j].Phenotype.Complexity()
   184  		if ci > cj {
   185  			return true // higher complexity is less
   186  		} else if ci == cj {
   187  			return f[i].Genotype.Id < f[j].Genotype.Id // least recent (older) is less
   188  		}
   189  	}
   190  	return false
   191  }