This repository has been archived by the owner on Jan 2, 2024. It is now read-only.
forked from MaxHalford/eaopt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
individual.go
98 lines (88 loc) · 2.52 KB
/
individual.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package eaopt
import (
"fmt"
"math"
"math/rand"
)
// An Individual wraps a Genome and contains the fitness assigned to the Genome.
type Individual struct {
Genome Genome `json:"genome"`
Fitness float64 `json:"fitness"`
Evaluated bool `json:"-"`
ID string `json:"id"`
}
// NewIndividual returns a fresh individual.
func NewIndividual(genome Genome, rng *rand.Rand) Individual {
return Individual{
Genome: genome,
Fitness: math.Inf(1),
Evaluated: false,
ID: randString(6, rng),
}
}
// String representation of an Individual. A tick (✔) or cross (✘) marker is
// added at the end to indicate if the Individual has been evaluated or not.
func (indi Individual) String() string {
if indi.Evaluated {
return fmt.Sprintf("%s - %.3f - %v", indi.ID, indi.Fitness, indi.Genome)
}
return fmt.Sprintf("%s - ??? - %v", indi.ID, indi.Genome)
}
// Clone an individual to produce a new individual with a different pointer and
// a different ID.
func (indi Individual) Clone(rng *rand.Rand) Individual {
var clone = Individual{
Fitness: indi.Fitness,
Evaluated: indi.Evaluated,
ID: randString(6, rng),
}
if indi.Genome == nil {
clone.Genome = nil
} else {
clone.Genome = indi.Genome.Clone()
}
return clone
}
// Evaluate the fitness of an individual. Don't evaluate individuals that have
// already been evaluated.
func (indi *Individual) Evaluate() error {
if indi.Evaluated {
return nil
}
var fitness, err = indi.Genome.Evaluate()
if err != nil {
return err
}
indi.Fitness = fitness
indi.Evaluated = true
return nil
}
// GetFitness returns the fitness of an Individual after making sure it has been
// evaluated.
func (indi *Individual) GetFitness() float64 {
indi.Evaluate()
return indi.Fitness
}
// Mutate an individual by calling the Mutate method of it's Genome.
func (indi *Individual) Mutate(rng *rand.Rand) {
indi.Genome.Mutate(rng)
indi.Evaluated = false
}
// Crossover an individual by calling the Crossover method of it's Genome.
func (indi *Individual) Crossover(mate Individual, rng *rand.Rand) {
indi.Genome.Crossover(mate.Genome, rng)
indi.Evaluated = false
mate.Evaluated = false
}
// IdxOfClosest returns the index of the closest individual from a slice of
// individuals based on the Metric field of a DistanceMemoizer.
func (indi Individual) IdxOfClosest(indis Individuals, dm DistanceMemoizer) (i int) {
var min = math.Inf(1)
for j, candidate := range indis {
var dist = dm.GetDistance(indi, candidate)
if dist < min {
min, i = dist, j
}
}
return i
}