|
| 1 | +package genetic_algorithm |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "math/rand" |
| 6 | +) |
| 7 | + |
| 8 | +const ( |
| 9 | + mutatorInvertExactLen = 0 |
| 10 | + mutatorInvertPercentageLen = 1 |
| 11 | +) |
| 12 | + |
| 13 | +// Mutator selects some part of the chromosome and inverts it |
| 14 | +type InvertMutator struct { |
| 15 | + probability float64 |
| 16 | + chromosomeConstructor EmptyChromosomeConstructor |
| 17 | + kind int |
| 18 | + fromExact int |
| 19 | + toExact int |
| 20 | + fromPercent float64 |
| 21 | + toPercent float64 |
| 22 | + |
| 23 | + temp GenesInterface |
| 24 | +} |
| 25 | + |
| 26 | +func newInvertMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor) *InvertMutator { |
| 27 | + if probability > 1 || probability < 0 { |
| 28 | + panic(fmt.Sprintf("Incorrect probability %v", probability)) |
| 29 | + } |
| 30 | + |
| 31 | + mutator := new(InvertMutator) |
| 32 | + |
| 33 | + mutator.probability = probability |
| 34 | + mutator.chromosomeConstructor = chromosomeConstructor |
| 35 | + |
| 36 | + return mutator |
| 37 | +} |
| 38 | + |
| 39 | +// Creates mutator that will invert part of chromosome that lays on interval [from:to] |
| 40 | +// Probability is applied to each chromosome. |
| 41 | +func NewInvertExactIntervalMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor, from, to int) *InvertMutator { |
| 42 | + if from > to || from < 0 || to < 1 { |
| 43 | + panic(fmt.Sprintf("Incorrect interval [%d:%d]", from, to)) |
| 44 | + } |
| 45 | + |
| 46 | + mutator := newInvertMutator(probability, chromosomeConstructor) |
| 47 | + |
| 48 | + mutator.kind = mutatorInvertExactLen |
| 49 | + mutator.fromExact = from |
| 50 | + mutator.toExact = to |
| 51 | + |
| 52 | + return mutator |
| 53 | +} |
| 54 | + |
| 55 | +// Creates mutator that will invert part of chromosome.Part's len defined by genesToInvert. |
| 56 | +// Probability is applied to each chromosome. |
| 57 | +func NewInvertExactMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor, genesToInvert int) *InvertMutator { |
| 58 | + return NewInvertExactIntervalMutator(probability, chromosomeConstructor, genesToInvert, genesToInvert) |
| 59 | +} |
| 60 | + |
| 61 | +// Creates mutator that will invert part of chromosome that lays on interval [from*chromLen : to*chromLen] |
| 62 | +// Probability is applied to each chromosome. |
| 63 | +func NewInvertPercentageIntervalMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor, from, to float64) *InvertMutator { |
| 64 | + if from > to || from < 0 || to < 0 || from > 1 || to > 1 { |
| 65 | + panic(fmt.Sprintf("Incorrect percentage interval [%v:%v]", from, to)) |
| 66 | + } |
| 67 | + |
| 68 | + mutator := newInvertMutator(probability, chromosomeConstructor) |
| 69 | + |
| 70 | + mutator.kind = mutatorInvertPercentageLen |
| 71 | + mutator.fromPercent = from |
| 72 | + mutator.toPercent = to |
| 73 | + |
| 74 | + return mutator |
| 75 | +} |
| 76 | + |
| 77 | +// Creates mutator that will invert part of chromosome. Part's len calcs as percentage * chromLen |
| 78 | +// Probability is applied to each chromosome. |
| 79 | +func NewInvertPercentageMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor, percentage float64) *InvertMutator { |
| 80 | + return NewInvertPercentageIntervalMutator(probability, chromosomeConstructor, percentage, percentage) |
| 81 | +} |
| 82 | + |
| 83 | +func (mutator *InvertMutator) Mutate(population Chromosomes) { |
| 84 | + for _, chrom := range population { |
| 85 | + if mutator.probability < rand.Float64() { |
| 86 | + continue |
| 87 | + } |
| 88 | + |
| 89 | + genesLen := chrom.Genes().Len() |
| 90 | + intervalLen := mutator.getIntervalLen(genesLen) |
| 91 | + from, to := mutator.getInterval(genesLen, intervalLen) |
| 92 | + |
| 93 | + mutator.mutate(chrom.Genes(), from, to) |
| 94 | + } |
| 95 | +} |
| 96 | +func (mutator *InvertMutator) getIntervalLen(genesLen int) int { |
| 97 | + if mutator.kind == mutatorInvertExactLen { |
| 98 | + return rand.Intn(mutator.toExact-mutator.fromExact+1) + mutator.fromExact |
| 99 | + } |
| 100 | + |
| 101 | + percent := rand.Float64()*(mutator.toPercent-mutator.fromPercent) + mutator.fromPercent |
| 102 | + return round(percent * float64(genesLen)) |
| 103 | +} |
| 104 | +func (mutator *InvertMutator) getInterval(genesLen, intervalLen int) (int, int) { |
| 105 | + if intervalLen > genesLen { |
| 106 | + panic(fmt.Sprintf("Interval bigger than chromosome. %d > %d", intervalLen, genesLen)) |
| 107 | + } |
| 108 | + |
| 109 | + firstPoint := rand.Intn(genesLen - intervalLen + 1) |
| 110 | + return firstPoint, firstPoint + intervalLen |
| 111 | +} |
| 112 | +func (mutator *InvertMutator) mutate(genes GenesInterface, from, to int) { |
| 113 | + genesLen := genes.Len() |
| 114 | + |
| 115 | + if mutator.temp == nil || mutator.temp.Len() != genesLen { |
| 116 | + mutator.temp = mutator.chromosomeConstructor(genesLen).Genes() |
| 117 | + } |
| 118 | + |
| 119 | + mutator.temp.Copy(genes, from, from, to) |
| 120 | + |
| 121 | + for i := from; i < to; i++ { |
| 122 | + ind := to + from - i - 1 |
| 123 | + genes.Set(i, mutator.temp.Get(ind)) |
| 124 | + } |
| 125 | +} |
0 commit comments