/
minimizer.go
104 lines (95 loc) · 2.11 KB
/
minimizer.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
99
100
101
102
103
104
// Package de implements Differential Evolution method of optimization.
// See http://en.wikipedia.org/wiki/Differential_evolution
package de
import (
"log"
"math"
"math/rand"
"time"
)
// Cost is an interface that an optimization problem should implement.
type Cost interface {
Cost([]float64) float64
}
// Minimizes cost function by evoluting the population of multiple agents.
type Minimizer struct {
Pop []*Agent // population of agents
CR float64 // crossover probability (default 0.9)
BestId int
rnd *rand.Rand
}
// Creates new minimizer:
// newcost - should return new value that satisfies Cost interface (it is called
// concurently by population of agents during minmizer initialization),
// n - number of entities in population,
// min, max - area for initial population.
func NewMinimizer(newcost func() Cost, n int, min, max []float64) *Minimizer {
if n < 4 {
log.Panic("population too small: ", n)
}
m := new(Minimizer)
m.CR = 0.9
m.Pop = make([]*Agent, n)
// Initialization of population
for i := range m.Pop {
m.Pop[i] = newAgent(min, max, newcost)
}
m.rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
return m
}
// Calculate next generation. Returns min and max cost in population.
func (m *Minimizer) NextGen() (minCost, maxCost float64) {
minCost = math.MaxFloat64
maxCost = -math.MaxFloat64
// Perform crossover
for i, x := range m.Pop {
f := 0.5 + m.rnd.Float64()*0.5
a, b, c := m.abc(i)
x.in <- args{a.x, b.x, c.x, f, m.CR}
}
// Get results
for i, x := range m.Pop {
c := <-x.out
if c < minCost {
minCost = c
m.BestId = i
}
if c > maxCost {
maxCost = c
}
}
return
}
// Stops all gorutines and invalidates m.
func (m *Minimizer) Delete() {
for _, x := range m.Pop {
x.in <- args{}
}
m.Pop = nil
}
// Returns three random agents different from Pop[i].
func (m *Minimizer) abc(i int) (a, b, c *Agent) {
n := len(m.Pop)
j := m.rnd.Intn(n - 1)
if j >= i {
j++
}
k := m.rnd.Intn(n - 2)
if k >= i {
k++
}
if k >= j {
k++
}
l := m.rnd.Intn(n - 3)
if l >= i {
l++
}
if l >= j {
l++
}
if l >= k {
l++
}
return m.Pop[j], m.Pop[k], m.Pop[l]
}