Skip to content

Commit

Permalink
Do some renaming to follow conventions (specifically "make" becomes "…
Browse files Browse the repository at this point in the history
…new")
  • Loading branch information
MaxHalford committed Jun 13, 2017
1 parent d3e88ce commit cc44927
Show file tree
Hide file tree
Showing 22 changed files with 153 additions and 152 deletions.
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,14 @@ func (X Vector) Crossover(Y gago.Genome, rng *rand.Rand) (gago.Genome, gago.Geno
return Vector(o1), Vector(o2)
}

// MakeVector returns a random vector by generating 2 values uniformally
// NewVector returns a random vector by generating 2 values uniformally
// distributed between -10 and 10.
func MakeVector(rng *rand.Rand) gago.Genome {
func NewVector(rng *rand.Rand) gago.Genome {
return Vector(gago.InitUnifFloat64(2, -10, 10, rng))
}

func main() {
var ga = gago.Generational(MakeVector)
var ga = gago.Generational(NewVector)
ga.Initialize()

fmt.Printf("Best fitness at generation 0: %f\n", ga.Best.Fitness)
Expand All @@ -153,11 +153,11 @@ func main() {

**More examples**

- [Cross-in-Tray (speciation)](examples/cross_in_tray/)
- [Grid TSP](examples/tsp_grid/main.go)
- [One Max problem](examples/one_max/main.go)
- [N-queens problem](examples/string_matching/)
- [String matching](examples/string_matching/main.go)
- [Cross-in-Tray (speciation)](https://github.com/MaxHalford/gago-examples/tree/master/cross_in_tray)
- [Grid TSP](https://github.com/MaxHalford/gago-examples/tree/master/tsp_grid)
- [One Max problem](https://github.com/MaxHalford/gago-examples/tree/master/one_max)
- [N-queens problem](https://github.com/MaxHalford/gago-examples/tree/master/n_queens)
- [String matching](https://github.com/MaxHalford/gago-examples/tree/master/string_matching)

## Background

Expand Down Expand Up @@ -258,7 +258,7 @@ Let's have a look at the GA struct.
```go
type GA struct {
// Fields that are provided by the user
MakeGenome GenomeMaker
GenomeFactory GenomeFactory
NPops int
PopSize int
Model Model
Expand All @@ -278,15 +278,15 @@ type GA struct {

You have to fill in the first 5 fields, the rest are generated when calling the `GA`'s `Initialize()` method.

- `MakeGenome` is a method that returns a random genome that you defined in the previous step. gago will use this method to produce an initial population. Again, gago provides some methods for common random genome generation.
- `GenomeFactory` is a method that returns a random genome that you defined in the previous step. gago will use this method to produce an initial population. Again, gago provides some methods for common random genome generation.
- `NPops` determines the number of populations that will be used.
- `PopSize` determines the number of individuals inside each population.
- `Model` determines how to use the genetic operators you chose in order to produce better solutions, in other words it's a recipe. A dedicated section is available in the [model section](#models).
- `Migrator` and `MigFrequency` should be provided if you want to exchange individuals between populations in case of a multi-population GA. If not the populations will be run independently. Again this is an advanced concept in the genetic algorithms field that you shouldn't deal with at first.
- `Speciator` will split each population in distinct species at each generation. Each specie will be evolved separately from the others, after all the species has been evolved they are regrouped.
- `Logger` is optional, you can read more about in the [logging section](#logging-population-statistics).

Essentially, only `MakeGenome`, `NPops`, `PopSize` and `Model` are required to initialize and run a GA.
Essentially, only `GenomeFactory`, `NPops`, `PopSize` and `Model` are required to initialize and run a GA.


### Running a GA
Expand Down
24 changes: 12 additions & 12 deletions crossover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import (

func TestCrossUniformFloat64(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
p1 = MakeVector(rng).(Vector)
p2 = MakeVector(rng).(Vector)
rng = newRandomNumberGenerator()
p1 = NewVector(rng).(Vector)
p2 = NewVector(rng).(Vector)
o1, o2 = CrossUniformFloat64(p1, p2, rng)
)
// Check lengths
Expand Down Expand Up @@ -90,7 +90,7 @@ func TestGNX(t *testing.T) {

func TestCrossGNXFloat64(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
rng = newRandomNumberGenerator()
p1 = []float64{1, 2, 3}
p2 = []float64{3, 2, 1}
o1, o2 = CrossGNXFloat64(p1, p2, 2, rng)
Expand All @@ -103,7 +103,7 @@ func TestCrossGNXFloat64(t *testing.T) {

func TestCrossGNXInt(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
rng = newRandomNumberGenerator()
p1 = []int{1, 2, 3}
p2 = []int{3, 2, 1}
o1, o2 = CrossGNXInt(p1, p2, 2, rng)
Expand All @@ -116,7 +116,7 @@ func TestCrossGNXInt(t *testing.T) {

func TestCrossGNXString(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
rng = newRandomNumberGenerator()
p1 = []string{"a", "b", "c"}
p2 = []string{"c", "b", "a"}
o1, o2 = CrossGNXString(p1, p2, 2, rng)
Expand Down Expand Up @@ -176,7 +176,7 @@ func TestPMX(t *testing.T) {

func TestCrossPMXFloat64(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
rng = newRandomNumberGenerator()
p1 = []float64{1, 2, 3}
p2 = []float64{3, 2, 1}
o1, o2 = CrossPMXFloat64(p1, p2, rng)
Expand All @@ -189,7 +189,7 @@ func TestCrossPMXFloat64(t *testing.T) {

func TestCrossPMXInt(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
rng = newRandomNumberGenerator()
p1 = []int{1, 2, 3}
p2 = []int{3, 2, 1}
o1, o2 = CrossPMXInt(p1, p2, rng)
Expand All @@ -202,7 +202,7 @@ func TestCrossPMXInt(t *testing.T) {

func TestCrossPMXString(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
rng = newRandomNumberGenerator()
p1 = []string{"a", "b", "c"}
p2 = []string{"c", "b", "a"}
o1, o2 = CrossPMXString(p1, p2, rng)
Expand Down Expand Up @@ -262,7 +262,7 @@ func TestOX(t *testing.T) {

func TestCrossOXFloat64(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
rng = newRandomNumberGenerator()
p1 = []float64{1, 2, 3}
p2 = []float64{3, 2, 1}
o1, o2 = CrossOXFloat64(p1, p2, rng)
Expand All @@ -275,7 +275,7 @@ func TestCrossOXFloat64(t *testing.T) {

func TestCrossOXInt(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
rng = newRandomNumberGenerator()
p1 = []int{1, 2, 3}
p2 = []int{3, 2, 1}
o1, o2 = CrossOXInt(p1, p2, rng)
Expand All @@ -288,7 +288,7 @@ func TestCrossOXInt(t *testing.T) {

func TestCrossOXString(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
rng = newRandomNumberGenerator()
p1 = []string{"a", "b", "c"}
p2 = []string{"c", "b", "a"}
o1, o2 = CrossOXString(p1, p2, rng)
Expand Down
4 changes: 2 additions & 2 deletions distance.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ type DistanceMemoizer struct {
nCalculations int // Total number of calls to Metric for testing purposes
}

// makeDistanceMemoizer initializes a DistanceMemoizer.
func makeDistanceMemoizer(metric Metric) DistanceMemoizer {
// newDistanceMemoizer initializes a DistanceMemoizer.
func newDistanceMemoizer(metric Metric) DistanceMemoizer {
return DistanceMemoizer{
Metric: metric,
Distances: make(map[string]map[string]float64),
Expand Down
2 changes: 1 addition & 1 deletion distance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

func TestDistanceMemoizer(t *testing.T) {
var (
dm = makeDistanceMemoizer(l1Distance)
dm = newDistanceMemoizer(l1Distance)
a = Individual{Genome: Vector{1, 1, 1}, ID: "1"}
b = Individual{Genome: Vector{3, 3, 3}, ID: "2"}
c = Individual{Genome: Vector{6, 6, 6}, ID: "3"}
Expand Down
32 changes: 16 additions & 16 deletions ga.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import (
// A GA contains population which themselves contain individuals.
type GA struct {
// Fields that are provided by the user
MakeGenome GenomeMaker `json:"-"`
NPops int `json:"-"`
PopSize int `json:"-"`
Model Model `json:"-"`
Migrator Migrator `json:"-"`
MigFrequency int `json:"-"` // Frequency at which migrations occur
Speciator Speciator `json:"-"`
Logger *log.Logger `json:"-"`
GenomeFactory GenomeFactory `json:"-"`
NPops int `json:"-"`
PopSize int `json:"-"`
Model Model `json:"-"`
Migrator Migrator `json:"-"`
MigFrequency int `json:"-"` // Frequency at which migrations occur
Speciator Speciator `json:"-"`
Logger *log.Logger `json:"-"`

// Fields that are generated at runtime
Populations Populations `json:"pops"`
Expand All @@ -31,9 +31,9 @@ type GA struct {
// Validate the parameters of a GA to ensure it will run correctly; some
// settings or combination of settings may be incoherent during runtime.
func (ga GA) Validate() error {
// Check the GenomeMaker presence
if ga.MakeGenome == nil {
return errors.New("GenomeMaker cannot be nil")
// Check the GenomeFactory presence
if ga.GenomeFactory == nil {
return errors.New("GenomeFactory cannot be nil")
}
// Check the number of populations is higher than 0
if ga.NPops < 1 {
Expand Down Expand Up @@ -84,16 +84,16 @@ func (ga *GA) findBest() {
// reset the GA entirely.
func (ga *GA) Initialize() {
ga.Populations = make([]Population, ga.NPops)
ga.rng = makeRandomNumberGenerator()
ga.rng = newRandomNumberGenerator()
var wg sync.WaitGroup
for i := range ga.Populations {
wg.Add(1)
go func(j int) {
defer wg.Done()
// Generate a population
ga.Populations[j] = makePopulation(
ga.Populations[j] = newPopulation(
ga.PopSize,
ga.MakeGenome,
ga.GenomeFactory,
randString(3, ga.rng),
)
// Evaluate its individuals
Expand All @@ -108,8 +108,8 @@ func (ga *GA) Initialize() {
}
wg.Wait()
// The initial best individual is initialized randomly
var rng = makeRandomNumberGenerator()
ga.Best = MakeIndividual(ga.MakeGenome(rng), rng)
var rng = newRandomNumberGenerator()
ga.Best = NewIndividual(ga.GenomeFactory(rng), rng)
ga.findBest()
}

Expand Down
12 changes: 6 additions & 6 deletions ga_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ func TestValidationSuccess(t *testing.T) {
}
}

func TestValidationGenomeMaker(t *testing.T) {
var genomeMaker = ga.MakeGenome
ga.MakeGenome = nil
func TestValidationGenomeFactory(t *testing.T) {
var genomeFactory = ga.GenomeFactory
ga.GenomeFactory = nil
if ga.Validate() == nil {
t.Error("Nil GenomeMaker should return an error")
t.Error("Nil GenomeFactory should return an error")
}
ga.MakeGenome = genomeMaker
ga.GenomeFactory = genomeFactory
}

func TestValidationNPopulations(t *testing.T) {
Expand Down Expand Up @@ -142,7 +142,7 @@ func TestDuration(t *testing.T) {

func TestSpeciateEvolveMerge(t *testing.T) {
var (
rng = makeRandomNumberGenerator()
rng = newRandomNumberGenerator()
pop = Population{ID: "42", rng: rng, Individuals: Individuals{}}
)
for i := 0; i < 7; i++ {
Expand Down
17 changes: 9 additions & 8 deletions individual.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ type Genome interface {
Crossover(genome Genome, rng *rand.Rand) (Genome, Genome)
}

// A GenomeMaker is a method that generates a new Genome with random properties.
type GenomeMaker func(rng *rand.Rand) Genome
// A GenomeFactory is a method that generates a new Genome with random
// properties.
type GenomeFactory func(rng *rand.Rand) Genome

// An Individual wraps a Genome and contains the fitness assigned to the Genome.
type Individual struct {
Expand All @@ -25,8 +26,8 @@ type Individual struct {
ID string `json:"id"`
}

// MakeIndividual returns a fresh individual.
func MakeIndividual(genome Genome, rng *rand.Rand) Individual {
// NewIndividual returns a fresh individual.
func NewIndividual(genome Genome, rng *rand.Rand) Individual {
return Individual{
Genome: genome,
Fitness: math.Inf(1),
Expand Down Expand Up @@ -65,8 +66,8 @@ func (indi *Individual) Mutate(rng *rand.Rand) {
func (indi Individual) Crossover(mate Individual, rng *rand.Rand) (Individual, Individual) {
var (
genome1, genome2 = indi.Genome.Crossover(mate.Genome, rng)
offspring1 = MakeIndividual(genome1, rng)
offspring2 = MakeIndividual(genome2, rng)
offspring1 = NewIndividual(genome1, rng)
offspring2 = NewIndividual(genome2, rng)
)
return offspring1, offspring2
}
Expand Down Expand Up @@ -99,10 +100,10 @@ func (indis Individuals) Clone(rng *rand.Rand) Individuals {
}

// Generate a slice of n new individuals.
func makeIndividuals(n int, gm GenomeMaker, rng *rand.Rand) Individuals {
func newIndividuals(n int, gf GenomeFactory, rng *rand.Rand) Individuals {
var indis = make(Individuals, n)
for i := range indis {
indis[i] = MakeIndividual(gm(rng), rng)
indis[i] = NewIndividual(gf(rng), rng)
}
return indis
}
Expand Down
Loading

0 comments on commit cc44927

Please sign in to comment.