individual.go 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package gago
  2. import (
  3. "fmt"
  4. "math"
  5. "math/rand"
  6. )
  7. // An Individual wraps a Genome and contains the fitness assigned to the Genome.
  8. type Individual struct {
  9. Genome Genome `json:"genome"`
  10. Fitness float64 `json:"fitness"`
  11. Evaluated bool `json:"-"`
  12. ID string `json:"id"`
  13. }
  14. // NewIndividual returns a fresh individual.
  15. func NewIndividual(genome Genome, rng *rand.Rand) Individual {
  16. return Individual{
  17. Genome: genome,
  18. Fitness: math.Inf(1),
  19. Evaluated: false,
  20. ID: randString(6, rng),
  21. }
  22. }
  23. // String representation of an Individual. A tick (✔) or cross (✘) marker is
  24. // added at the end to indicate if the Individual has been evaluated or not.
  25. func (indi Individual) String() string {
  26. var evalSymbol = map[bool]string{
  27. true: "✔",
  28. false: "✘",
  29. }[indi.Evaluated]
  30. return fmt.Sprintf("%s - %.3f - %v %s", indi.ID, indi.Fitness, indi.Genome, evalSymbol)
  31. }
  32. // Clone an individual to produce a new individual with a different pointer and
  33. // a different ID.
  34. func (indi Individual) Clone(rng *rand.Rand) Individual {
  35. return Individual{
  36. Genome: indi.Genome.Clone(),
  37. Fitness: indi.Fitness,
  38. Evaluated: indi.Evaluated,
  39. ID: randString(6, rng),
  40. }
  41. }
  42. // Evaluate the fitness of an individual. Don't evaluate individuals that have
  43. // already been evaluated.
  44. func (indi *Individual) Evaluate() {
  45. if !indi.Evaluated {
  46. indi.Fitness = indi.Genome.Evaluate()
  47. indi.Evaluated = true
  48. }
  49. }
  50. // GetFitness returns the fitness of an Individual after making sure it has been
  51. // evaluated.
  52. func (indi *Individual) GetFitness() float64 {
  53. indi.Evaluate()
  54. return indi.Fitness
  55. }
  56. // Mutate an individual by calling the Mutate method of it's Genome.
  57. func (indi *Individual) Mutate(rng *rand.Rand) {
  58. indi.Genome.Mutate(rng)
  59. indi.Evaluated = false
  60. }
  61. // Crossover an individual by calling the Crossover method of it's Genome.
  62. func (indi Individual) Crossover(mate Individual, rng *rand.Rand) (Individual, Individual) {
  63. var (
  64. genome1, genome2 = indi.Genome.Crossover(mate.Genome, rng)
  65. offspring1 = NewIndividual(genome1, rng)
  66. offspring2 = NewIndividual(genome2, rng)
  67. )
  68. return offspring1, offspring2
  69. }
  70. // IdxOfClosest returns the index of the closest individual from a slice of
  71. // individuals based on the Metric field of a DistanceMemoizer.
  72. func (indi Individual) IdxOfClosest(indis Individuals, dm DistanceMemoizer) (i int) {
  73. var min = math.Inf(1)
  74. for j, candidate := range indis {
  75. var dist = dm.GetDistance(indi, candidate)
  76. if dist < min {
  77. min, i = dist, j
  78. }
  79. }
  80. return i
  81. }