individuals.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package gago
  2. import (
  3. "math"
  4. "math/rand"
  5. "sort"
  6. "strings"
  7. )
  8. // Individuals is a convenience type, methods that belong to an Individual can
  9. // be called declaratively.
  10. type Individuals []Individual
  11. // String representation of a slice of Individuals.
  12. func (indis Individuals) String() string {
  13. var str string
  14. for _, indi := range indis {
  15. str += indi.String() + "\n"
  16. }
  17. return strings.TrimSuffix(str, "\n")
  18. }
  19. // Clone returns the same exact same slice of individuals but with different
  20. // pointers and ID fields.
  21. func (indis Individuals) Clone(rng *rand.Rand) Individuals {
  22. var clones = make(Individuals, len(indis))
  23. for i, indi := range indis {
  24. clones[i] = indi.Clone(rng)
  25. }
  26. return clones
  27. }
  28. // Generate a slice of n new individuals.
  29. func newIndividuals(n int, gf GenomeFactory, rng *rand.Rand) Individuals {
  30. var indis = make(Individuals, n)
  31. for i := range indis {
  32. indis[i] = NewIndividual(gf(rng), rng)
  33. }
  34. return indis
  35. }
  36. // Evaluate each individual.
  37. func (indis Individuals) Evaluate() {
  38. for i := range indis {
  39. indis[i].Evaluate()
  40. }
  41. }
  42. // Mutate each individual.
  43. func (indis Individuals) Mutate(mutRate float64, rng *rand.Rand) {
  44. for i := range indis {
  45. if rng.Float64() < mutRate {
  46. indis[i].Mutate(rng)
  47. }
  48. }
  49. }
  50. // SortByFitness ascendingly sorts individuals by fitness.
  51. func (indis Individuals) SortByFitness() {
  52. var less = func(i, j int) bool { return indis[i].Fitness < indis[j].Fitness }
  53. sort.Slice(indis, less)
  54. }
  55. // IsSortedByFitness checks if individuals are ascendingly sorted by fitness.
  56. func (indis Individuals) IsSortedByFitness() bool {
  57. var less = func(i, j int) bool { return indis[i].Fitness < indis[j].Fitness }
  58. return sort.SliceIsSorted(indis, less)
  59. }
  60. // SortByDistanceToMedoid sorts Individuals according to their distance to the
  61. // medoid. The medoid is the Individual that has the lowest average distance to
  62. // the rest of the Individuals.
  63. func (indis Individuals) SortByDistanceToMedoid(dm DistanceMemoizer) {
  64. var (
  65. avgDists = calcAvgDistances(indis, dm)
  66. less = func(i, j int) bool {
  67. return avgDists[indis[i].ID] < avgDists[indis[j].ID]
  68. }
  69. )
  70. sort.Slice(indis, less)
  71. }
  72. // Extract the fitness of a slice of individuals into a float64 slice.
  73. func (indis Individuals) getFitnesses() []float64 {
  74. var fitnesses = make([]float64, len(indis))
  75. for i, indi := range indis {
  76. fitnesses[i] = indi.Fitness
  77. }
  78. return fitnesses
  79. }
  80. // FitMin returns the best fitness of a slice of individuals.
  81. func (indis Individuals) FitMin() float64 {
  82. if indis.IsSortedByFitness() {
  83. return indis[0].Fitness
  84. }
  85. return minFloat64s(indis.getFitnesses())
  86. }
  87. // FitMax returns the best fitness of a slice of individuals.
  88. func (indis Individuals) FitMax() float64 {
  89. if indis.IsSortedByFitness() {
  90. return indis[len(indis)-1].Fitness
  91. }
  92. return maxFloat64s(indis.getFitnesses())
  93. }
  94. // FitAvg returns the average fitness of a slice of individuals.
  95. func (indis Individuals) FitAvg() float64 {
  96. return meanFloat64s(indis.getFitnesses())
  97. }
  98. // FitStd returns the standard deviation of the fitness of a slice of
  99. // individuals.
  100. func (indis Individuals) FitStd() float64 {
  101. return math.Sqrt(varianceFloat64s(indis.getFitnesses()))
  102. }