Skip to content

Commit

Permalink
add new selecters (#31)
Browse files Browse the repository at this point in the history
* add new selecters

* stochastic sampling
  • Loading branch information
khezen committed Mar 13, 2021
1 parent 17fff12 commit 0610664
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 49 deletions.
9 changes: 7 additions & 2 deletions arbitrer.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,14 @@ func NewProportionalToRankArbitrer() Arbitrer {
return selecterBasedArbitrer{NewProportionalToRankSelecter()}
}

// NewStochasticUniversalSamplingArbitrer - based on fitness value
func NewStochasticUniversalSamplingArbitrer() Arbitrer {
return selecterBasedArbitrer{NewStochasticUniversalSamplingSelecter()}
}

// NewTournamentArbitrer - High Fitness increase chances to come out vcitorious from a duel
func NewTournamentArbitrer() Arbitrer {
return selecterBasedArbitrer{NewTournamentSelecter()}
func NewTournamentArbitrer(p float64) Arbitrer {
return selecterBasedArbitrer{NewTournamentSelecter(p)}
}

// NewTruncationArbitrer - take the highest fitness
Expand Down
2 changes: 1 addition & 1 deletion arbitrer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func TestArbitrerTruncation(t *testing.T) {
}

func TestArbitrerTournament(t *testing.T) {
testArbitrer(t, NewTournamentArbitrer())
testArbitrer(t, NewTournamentArbitrer(1))
}

func TestArbitrerRandom(t *testing.T) {
Expand Down
125 changes: 80 additions & 45 deletions selecter.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,67 +70,102 @@ func NewProportionalToFitnessSelecter() Selecter {
return proportionalToFitnessSelecter{}
}

type tournamentSelecter struct{}
type stochasticUniversalSampling struct{}

func (s tournamentSelecter) Select(pop Population, survivorsSize int) (survivors, deads Population, err error) {
func (s stochasticUniversalSampling) Select(pop Population, survivorsSize int) (survivors, deads Population, err error) {
checkSelectParams(survivorsSize)
if survivorsSize >= pop.Len() {
return pop, nil, nil
}
newPop := pop.New(pop.Cap())
for newPop.Len() < survivorsSize {
var i, j = rand.Intn(pop.Len()), rand.Intn(pop.Len())
if i == j {
switch i {
case pop.Len() - 1:
j = i - 1
default:
j = i + 1
survivors = pop.New(pop.Cap())
deads = pop.New(pop.Cap() - survivorsSize)
var (
minIndiv = pop.Min()
minFit = minIndiv.Fitness()
offset float64
totalFit float64
)
if minFit < 0 {
offset = -minFit
}
pop.Each(func(indiv Individual) bool {
totalFit += indiv.Fitness() + offset
return true
})
step := totalFit / float64(survivorsSize)
start := rand.Float64() * step
milestones := make([]float64, 0, survivorsSize)
for i := 0; i < survivorsSize; i++ {
milestones = append(milestones, start+float64(i)*step)
}
var (
fitSum float64
indiv Individual
isSelected bool
i int
)
pop.Sort()
for _, milestone := range milestones {
isSelected = false
for !isSelected {
indiv = pop.Get(i)
fitSum += indiv.Fitness() + offset
isSelected = fitSum >= milestone
if isSelected {
survivors.Add(indiv)
} else {
deads.Add(indiv)
}
i++
}
survivorIndex := s.fightForYourLives(pop, i, j)
indiv := pop.Get(survivorIndex)
pop.RemoveAt(survivorIndex)
newPop.Add(indiv)
}
return newPop, pop, nil
pop.Close()
return survivors, deads, nil
}

func (s tournamentSelecter) fightForYourLives(pop Population, index1 int, index2 int) (survivorIndex int) {
i1, i2 := pop.Get(index1), pop.Get(index2)
r1, r2 := i1.Fitness(), i2.Fitness()
offset := s.computeOffset(r1, r2)
r1 += offset
r2 += offset
total := r1 + r2
switch {
case total == 0, rand.Float64() <= r1/total:
return index1
default:
return index2
}
// NewStochasticUniversalSamplingSelecter is the constructor for selecter based on fitness value
func NewStochasticUniversalSamplingSelecter() Selecter {
return stochasticUniversalSampling{}
}

type tournamentSelecter struct {
p float64
}

func (s tournamentSelecter) computeOffset(r1, r2 float64) float64 {
var offset float64
switch {
case r1 < 0:
offset += -r1
case r1 > 0:
offset += r1
func (s tournamentSelecter) Select(pop Population, survivorsSize int) (survivors, deads Population, err error) {
checkSelectParams(survivorsSize)
if survivorsSize >= pop.Len() {
return pop, nil, nil
}
switch {
case r2 < 0:
offset += -r2
case r2 > 0:
offset += r2
survivors = pop.New(pop.Cap())
var leftovers Population
var popLen int
pop.Sort()
for survivors.Len() < survivorsSize {
popLen = pop.Len()
leftovers = pop.New(pop.Cap() - survivorsSize + survivors.Len())
for i := 0; i < popLen; i++ {
indiv := pop.Get(i)
if survivors.Len() >= survivorsSize {
leftovers.Add(indiv)
continue
}
draw := rand.Float64()
if draw <= s.p {
survivors.Add(indiv)
} else {
leftovers.Add(indiv)
}
}
pop.Close()
pop = leftovers
}
return offset
return survivors, pop, nil
}

// NewTournamentSelecter is the constructor for tournament selecter. High Fitness increase chances to come out vitorious from a duel
func NewTournamentSelecter() Selecter {
return tournamentSelecter{}
// NewTournamentSelecter is the constructor for tournament selecter. High rank increase chances to be selected
func NewTournamentSelecter(p float64) Selecter {
return tournamentSelecter{p}
}

type truncationSelecter struct{}
Expand Down
2 changes: 1 addition & 1 deletion selecter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func TestSelecterTruncation(t *testing.T) {
}

func TestSelecterTournament(t *testing.T) {
testSelecter(t, NewTournamentSelecter())
testSelecter(t, NewTournamentSelecter(1))
}

func TestSelecterRandom(t *testing.T) {
Expand Down

0 comments on commit 0610664

Please sign in to comment.