Giter VIP home page Giter VIP logo

maxhalford / eaopt Goto Github PK

View Code? Open in Web Editor NEW
875.0 875.0 98.0 584 KB

:four_leaf_clover: Evolutionary optimization library for Go (genetic algorithm, partical swarm optimization, differential evolution)

Home Page: https://pkg.go.dev/github.com/MaxHalford/eaopt

License: MIT License

Go 100.00%
differential-evolution evolutionary-algorithms evolutionary-computation genetic-algorithm go machine-learning metaheuristics optimization parallel particle-swarm-optimization speciation

eaopt's Introduction

Hello there ๐Ÿ‘‹

I'm Max, a data scientist working in the climate industry at Carbonfact.

I lead The Fellowship of Online Machine Learning, which is a group of people who enjoy researching and implementing online algorithms. In particular, we develop and maintain River.

I teach data science to graduate students at the Toulouse School of Economics. You can find the course content here.

eaopt's People

Contributors

bradleyjkemp avatar chriswalz avatar emgrasmeder avatar ephraimkunz avatar jaypeeteedee avatar jjr90 avatar maxhalford avatar pboyer avatar qmuntal avatar salbertson avatar smousa avatar spakin avatar stewartthomson avatar tanghaibao avatar ug88jdm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

eaopt's Issues

Panic when running preset Alignment

Maybe you can tell me if I am doing something wrong here? All the code is doing is initializing the preset.

panic: invalid argument to Intn

goroutine 6 [running]:
panic(0x4c88c0, 0xc42000a870)
    ~/.gvm/gos/go1.7.1/src/runtime/panic.go:500 +0x1a1
math/rand.(*Rand).Intn(0xc42000e5c0, 0x0, 0xc42000a866)
    ~/.gvm/gos/go1.7.1/src/math/rand/rand.go:116 +0xd0
github.com/MaxHalford/gago.InitUniformS.Apply(0x589780, 0x0, 0x0, 0xc42007c000, 0xc42000e5c0)
    ~/.gvm/pkgsets/go1.7.1/global/src/github.com/MaxHalford/gago/initializing.go:52 +0x57
github.com/MaxHalford/gago.(*InitUniformS).Apply(0xc42000e5a0, 0xc42007c000, 0xc42000e5c0)
    <autogenerated>:26 +0x78
github.com/MaxHalford/gago.makePopulation(0x1e, 0x12, 0x55a540, 0xc420010210, 0x55a440, 0xc42000e5a0, 0x0, 0x0, 0x0, 0x0, ...)
    ~/.gvm/pkgsets/go1.7.1/global/src/github.com/MaxHalford/gago/population.go:30 +0x1e1
github.com/MaxHalford/gago.(*GA).Initialize.func1(0xc42000a680, 0xc42005aa90, 0x1)
    ~/.gvm/pkgsets/go1.7.1/global/src/github.com/MaxHalford/gago/ga.go:95 +0x9f
created by github.com/MaxHalford/gago.(*GA).Initialize
    ~/.gvm/pkgsets/go1.7.1/global/src/github.com/MaxHalford/gago/ga.go:100 +0x144

Pass aditional data in Evaluate function

Hi

I need to access some data (which is not contained in Genome) to compute fitness. I looked in the documentation but didn't find a way to pass additional data to the Evaluate function. One option would be using global variables, but i think that is not the best way.

Do you have any ideas?

tag a new release

With go modules, "go get github.com/MaxHalford/eaopt" will fetch v0.1.0, which is very old. Can you tag a new release, say v0.2.0?

Multiple Objectives

Dear all,

from a scan of the (very nicely done) documentation, am I right, that eaopt currently does not support multiple objectives for optimization in evolutionary algorithms (incl. getting the pareto-optimal solutions)?

This might also be a point being clarified in the abstract, assisting the choose-a-library process :)

Best,
Lukas

More generation statistics?

Hey --

First of all, thanks so much for such awesome documentation. I've been doing GA stuff for a while, and seeing the "a lot of intellectual fog around the concept of genetic algorithms" quote made me happy.

Anyway, can't wait to use this.

One thing that I miss about using GENESIS system by Grefenstette was that it kept track of the number of gene-bits that were "lost" and those that were "converged". The lost bits were bits that were (in a specific point on the genome) all 1 or all 0. The converged ones were mostly the same (maybe 70%?).

It was a very useful metric to let you know when the system had, effectively, hit a local minima.

Parallelizing Individual Evaluate() calls?

Hi! Thanks for writing gago - it is very useful. I was in the middle of writing my own GA loop, when I realized I shouldn't be reinventing the wheel and stumbled accross your library.

per the docs:

Talking about parallelism, there is a reason why the populations are run in parallel and not the individuals. First of all for parallelism at an individual level each individual would have to be assigned a new random number generator, which isn't very efficient. Second of all, even though Golang has an efficient concurrency model, spawning routines nonetheless has an overhead. It's simply not worth using a routine for each individual because operations at an individual level are often not time consuming enough.

This makes sense for GA operations, specifically those that require an RNG - mutate, crossover, et al. Those generally are fairly fast too, so the argument against overhead is totally valid.

With that said, my Evaluate() function is relatively expensive (upwards to 1 second for each call) and already does not have access to the population's RNG. Would it make sense then to parallelize Evaluate() calls on individuals within a population? We could make this default to off for use cases where the Evaluate() function is fast and doing this would just cause overhead.

Let me know what you think. If this sounds good, I'll be glad to work on it when I get a chance and submit a PR. If you have any implementation suggestions / preferences, let me know too

ga.Best is genome with the lowest fitness?

Hey There, I'm new to genetic algorithms and i'm enjoying it a lot. Especially with this awesome library. On thing seems odd to me, as I understand it correctly the method Population.SortByFitness() seems to sort ascendingly and the GA.Best member is the individual at the top of this list. i.e the one with the lowest fitness.

Is this a defacto standard in the gentic algorithm world? It would logical to have the genome with the highest fitness to be the "best"?

Thank you!

Very big repository

Is it possible to separate the big files (eg. those in examples) from the core library?

My network speed is very slow that it takes a very long time to clone the repository......

I think it's around 100MiB........(still cloning Receiving objects: 15% (266/1694), 16.08 MiB | 180.00 KiB/s)

Crossover method not modifying genome

Hello @MaxHalford ,

Thanks for making a cool open source project! It's been interesting to learn about genetic algorithms by working with it. I'm also new to golang, so I may be missing something, but I'm having issues getting my Crossover function to work. When I set a pointer receiver (indicated here as the way to modify variables https://tour.golang.org/methods/4 ), I get a build error like below:

func (r *Route) Crossover(s eaopt.Genome, rng *rand.Rand) {

cannot use nearestNeighborRoute (type Route) as type eaopt.Genome in return argument:
	Route does not implement eaopt.Genome (Crossover method has pointer receiver)

.. When I change this to not being a pointer, it builds and executes
func (r Route) Crossover(s eaopt.Genome, rng *rand.Rand) {

at the end of the Crossover method, I'm assigning the new offspring to the r variable, but when I step thru the code from individual.go, the genome is unchanged

// bottom of my Crossover method:
r = offspring1

// in individual.go, indi.Genome is unchanged, it has the original r value, not the new crossover one.
func (indi *Individual) Crossover(mate Individual, rng *rand.Rand) {
	indi.Genome.Crossover(mate.Genome, rng)
	indi.Evaluated = false
	mate.Evaluated = false
}

I saw the note about how slices work better, so I changed my code to use Route instead of RouteState, which is a slice of Deliveries, but still seeing the issue

old data structure:

type RouteState struct {
	Deliveries []*Delivery
}

new data structure:
type Route []*Delivery

Crash...

Hello,

This may be my fault (almost certainly is) but it may be enlightening. I'll triple-check my code.

So first, from the Generation step down to the GA # 4 has a minimum is from my Callback routine.

Interestingly, it looks like it doesn't get called for the next few generations, and then the crash comes.

My setup is:

	var ga = gago.Generational(MakeNewVectorFunc(NUM, -0.1, 0.1))
	ga.NPops = 5
	ga.PopSize = 250
	ga.Speciator = gago.SpecKMedoids{
		K:             10,
		MinPerCluster: 10,
		Metric:        l1Distance,
		MaxIterations: 5,
	}
	ga.Callback = checkStats
	ga.Initialize()

I stole the l1Distance bodily from your source... I'll tell you where to send the ransom money :-)

here's the backtrace info:

Generation step took 3m14.626519066s
GA has 5 Populations.
GA 0 has 250 individuals.
GA # 0 has a minimum 4302236.000000000000, maximum 20046975.000000000000
GA 1 has 250 individuals.
GA # 1 has a minimum 4387752.000000000000, maximum 20046975.000000000000
GA 2 has 250 individuals.
GA # 2 has a minimum 4315952.000000000000, maximum 20046975.000000000000
GA 3 has 250 individuals.
GA # 3 has a minimum 4276399.000000000000, maximum 20046975.000000000000
GA 4 has 250 individuals.
GA # 4 has a minimum 4256291.000000000000, maximum 20046975.000000000000
Best fitness at generation    5: 3675431.000000
Best fitness at generation    6: 3675431.000000
Best fitness at generation    7: 3675431.000000
Best fitness at generation    8: 3675431.000000
panic: runtime error: index out of range

goroutine 65 [running]:
github.com/MaxHalford/gago.SpecKMedoids.Apply(0xa, 0xa, 0x146ed90, 0x5, 0xc42324a000, 0xfa, 0xfa, 0xc420014e70, 0x0, 0x0, ...)
        /Volumes/Second/Chris/hacks/gofigure/src/github.com/MaxHalford/gago/speciation.go:60 +0x754
github.com/MaxHalford/gago.(*SpecKMedoids).Apply(0xc42000c220, 0xc42324a000, 0xfa, 0xfa, 0xc420014e70, 0x0, 0x0, 0x0, 0x0, 0x0)
        <autogenerated>:85 +0xa0
github.com/MaxHalford/gago.(*Population).speciateEvolveMerge(0xc4200e8240, 0x1627a40, 0xc42000c220, 0x16279c0, 0xc42000c180, 0x1, 0x3)
        /Volumes/Second/Chris/hacks/gofigure/src/github.com/MaxHalford/gago/ga.go:181 +0x77
github.com/MaxHalford/gago.(*GA).Enhance.func1(0x8, 0x146f890)
        /Volumes/Second/Chris/hacks/gofigure/src/github.com/MaxHalford/gago/ga.go:142 +0x97
golang.org/x/sync/errgroup.(*Group).Go.func1(0xc420010480, 0xc422890150)
        /Volumes/Second/Chris/hacks/gofigure/src/golang.org/x/sync/errgroup/errgroup.go:58 +0x57
created by golang.org/x/sync/errgroup.(*Group).Go
        /Volumes/Second/Chris/hacks/gofigure/src/golang.org/x/sync/errgroup/errgroup.go:66 +0x66
exit status 2

Non-canonical roulette wheel is being built relative to a 'random' fitness?

Background

This first part is not an issue, just something I was sorta-curious about.

I notice the special transformation thingy you do on the fitnesses in buildWheel() (before building the wheel), causes individuals with zero fitness to still have some probability of selection, whereas in the textbook implementation they would not.

Example:
http://www.geatbx.com/docu/algindex-02.html#P363_18910

Unless I'm mistaken, the canonical/textbook implementation would be simply:

func buildWheel(fitnesses []float64) []float64 {
	return cumsum(divide(fitnesses, sumFloat64s(fitnesses)))
}

Comparison of the individual probabilities before cumsuming (scroll right):

Individual 1 2 3 4 5 6 7 8 9 10 11
Fitness -2 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0
Canonical probability 0.18 0.16 0.15 0.13 0.11 0.09 0.07 0.05 0.04 0.02 0.00
eaopt probability 0.14 0.13 0.12 0.11 0.10 0.09 0.08 0.07 0.06 0.05 0.05

(Some entries in 1st row differ from the above webpage by +/- 0.01, possibly due to rounding)

I guess I'm confused what this is for, as I've tried Googling and thinking, but can't figure it out. ๐Ÿ˜• ๐Ÿ˜…

Issue

SelRouletteWheel Apply() doesn't sort its input individuals.

As a result, the index n-1 in wheel[i] = fitnesses[n-1] - v + 1 isn't guaranteed to be the "worst" individual, if that's what it's supposed to be. (As it is, n-1 could be any 'random' fitness.)

However, because I don't understand the purpose of this preprocessing, I can't actually prove this is a bug, it just looks like one.

For example, ModDownToSize applies a Selector on append(offsprings, pop.Individuals...) - not sorted by fitness.

It's worth noting, I don't think the canonical version of buildWheel() would require sorting.

CrossCX and CrossERX relies on hashable types

I have a genome which isn't hashable. When I run my application, it panics:

panic: runtime error: hash of unhashable type scheduler.ScheduleRequest

goroutine 20 [running]:
github.com/JensRantil/eaopt.getNeighbours(0x118e300, 0xc0000990a0, 0xc000099140)
	/Users/jrantil/go/pkg/mod/github.com/!jens!rantil/[email protected]/slice.go:70 +0xfd
github.com/JensRantil/eaopt.CrossERX(0x118e300, 0xc0000990a0, 0x118e300, 0xc0000990c0)
	/Users/jrantil/go/pkg/mod/github.com/!jens!rantil/[email protected]/crossover.go:262 +0x156
github.com/JensRantil/meeting-scheduler.(*solution).Crossover(0xc000099040, 0x118d280, 0xc000099080, 0xc000076360)
	/Users/jrantil/src/meeting-scheduler/lib.go:163 +0xa3
github.com/JensRantil/eaopt.(*Individual).Crossover(...)
	/Users/jrantil/go/pkg/mod/github.com/!jens!rantil/[email protected]/individual.go:82
github.com/JensRantil/eaopt.generateOffsprings(0x1e, 0xc0000bc000, 0x1e, 0x1e, 0x118c400, 0xc00008a070, 0x3fe6666666666666, 0xc000076360, 0x110b8b9, 0x116362b, ...)
	/Users/jrantil/go/pkg/mod/github.com/!jens!rantil/[email protected]/models.go:32 +0x362
github.com/JensRantil/eaopt.ModGenerational.Apply(0x118c400, 0xc00008a070, 0x3fe0000000000000, 0x3fe6666666666666, 0xc000088640, 0xf, 0x0)
	/Users/jrantil/go/pkg/mod/github.com/!jens!rantil/[email protected]/models.go:64 +0x8c
github.com/JensRantil/eaopt.(*GA).evolve.func1(0xc000088640, 0xc00003ef60, 0x10759e6)
	/Users/jrantil/go/pkg/mod/github.com/!jens!rantil/[email protected]/ga.go:102 +0x240
github.com/JensRantil/eaopt.Populations.Apply.func1(0xc00003ef68, 0xc00003efc0)
	/Users/jrantil/go/pkg/mod/github.com/!jens!rantil/[email protected]/population.go:56 +0x45
golang.org/x/sync/errgroup.(*Group).Go.func1(0xc000076f90, 0xc000076fc0)
	/Users/jrantil/go/pkg/mod/golang.org/x/[email protected]/errgroup/errgroup.go:57 +0x64
created by golang.org/x/sync/errgroup.(*Group).Go
	/Users/jrantil/go/pkg/mod/golang.org/x/[email protected]/errgroup/errgroup.go:54 +0x66
FAIL	github.com/JensRantil/meeting-scheduler	0.227s

and

panic: runtime error: hash of unhashable type scheduler.ScheduleRequest

goroutine 20 [running]:
github.com/MaxHalford/eaopt.newIndexLookup(0x118c560, 0xc00009b120, 0x20)
	/Users/jrantil/go/pkg/mod/github.com/!max!halford/eaopt@v0.0.0-20191122194827-37dd3a71cb482d1990b40d439adbd976f27fc095/slice.go:33 +0x84
github.com/MaxHalford/eaopt.getCycles(0x118c560, 0xc00009b120, 0x118c560, 0xc00009b140, 0x5a0, 0x114c940, 0x1267960)
	/Users/jrantil/go/pkg/mod/github.com/!max!halford/eaopt@v0.0.0-20191122194827-37dd3a71cb482d1990b40d439adbd976f27fc095/slice.go:42 +0x50
github.com/MaxHalford/eaopt.CrossCX(0x118c560, 0xc00009b120, 0x118c560, 0xc00009b140)
	/Users/jrantil/go/pkg/mod/github.com/!max!halford/eaopt@v0.0.0-20191122194827-37dd3a71cb482d1990b40d439adbd976f27fc095/crossover.go:220 +0xc6
github.com/JensRantil/meeting-scheduler.(*solution).Crossover(0xc00009b0c0, 0x118b540, 0xc00009b100, 0xc000078360)
	/Users/jrantil/src/meeting-scheduler/lib.go:163 +0xa3
github.com/MaxHalford/eaopt.(*Individual).Crossover(...)
	/Users/jrantil/go/pkg/mod/github.com/!max!halford/eaopt@v0.0.0-20191122194827-37dd3a71cb482d1990b40d439adbd976f27fc095/individual.go:82
github.com/MaxHalford/eaopt.generateOffsprings(0x1e, 0xc0000be000, 0x1e, 0x1e, 0x118a6c0, 0xc00008c070, 0x3fe6666666666666, 0xc000078360, 0x110a809, 0x1161cab, ...)
	/Users/jrantil/go/pkg/mod/github.com/!max!halford/eaopt@v0.0.0-20191122194827-37dd3a71cb482d1990b40d439adbd976f27fc095/models.go:32 +0x362
github.com/MaxHalford/eaopt.ModGenerational.Apply(0x118a6c0, 0xc00008c070, 0x3fe0000000000000, 0x3fe6666666666666, 0xc00008a640, 0xf, 0x0)
	/Users/jrantil/go/pkg/mod/github.com/!max!halford/eaopt@v0.0.0-20191122194827-37dd3a71cb482d1990b40d439adbd976f27fc095/models.go:64 +0x8c
github.com/MaxHalford/eaopt.(*GA).evolve.func1(0xc00008a640, 0xc00003ef60, 0x10755b6)
	/Users/jrantil/go/pkg/mod/github.com/!max!halford/eaopt@v0.0.0-20191122194827-37dd3a71cb482d1990b40d439adbd976f27fc095/ga.go:102 +0x240
github.com/MaxHalford/eaopt.Populations.Apply.func1(0xc00003ef68, 0xc00003efc0)
	/Users/jrantil/go/pkg/mod/github.com/!max!halford/eaopt@v0.0.0-20191122194827-37dd3a71cb482d1990b40d439adbd976f27fc095/population.go:56 +0x45
golang.org/x/sync/errgroup.(*Group).Go.func1(0xc000078f90, 0xc000078fc0)
	/Users/jrantil/go/pkg/mod/golang.org/x/[email protected]/errgroup/errgroup.go:57 +0x64
created by golang.org/x/sync/errgroup.(*Group).Go
	/Users/jrantil/go/pkg/mod/golang.org/x/[email protected]/errgroup/errgroup.go:54 +0x66
FAIL	github.com/JensRantil/meeting-scheduler	0.229s

Assuming that interface{} is hashable is probably a bad idea.

Minimum score goes up rather than down sometimes

I'm trying to use your library, but I'm getting some really strange results sometimes. For certain models, the population seems to be getting worse (fitness function going up) as time goes on rather than better.

Here's one configuration I used:

		ga = gago.GA {
			NewGenome: ScheduleFactory,
			NPops:     2,
			PopSize:   200,
			Model: gago.ModMutationOnly {
				NChosen: 50,
				Selector: gago.SelElitism { },
				Strict: true,
			},
		}

And here is some sample output from the log:

schedule.go 2018/06/01 10:26:09 pop_id=IJN min=-42968.000000 max=-30081.000000 avg=-37780.345000 std=2289.283752
schedule.go 2018/06/01 10:26:09 pop_id=UIe min=-43257.000000 max=-30794.000000 avg=-38022.870000 std=2217.460431
schedule.go 2018/06/01 10:26:09 pop_id=UIe min=-40642.000000 max=-30794.000000 avg=-37369.045000 std=1836.562951
schedule.go 2018/06/01 10:26:09 pop_id=IJN min=-42115.000000 max=-30081.000000 avg=-37158.315000 std=1909.202324
schedule.go 2018/06/01 10:26:09 pop_id=UIe min=-40086.000000 max=-29913.000000 avg=-36747.050000 std=1707.612365
schedule.go 2018/06/01 10:26:09 pop_id=IJN min=-41925.000000 max=-30081.000000 avg=-36540.960000 std=1655.269854
schedule.go 2018/06/01 10:26:09 pop_id=UIe min=-39933.000000 max=-29913.000000 avg=-36240.105000 std=1729.159343
schedule.go 2018/06/01 10:26:09 pop_id=IJN min=-38890.000000 max=-30081.000000 avg=-36017.890000 std=1539.559852
schedule.go 2018/06/01 10:26:09 pop_id=IJN min=-38513.000000 max=-29207.000000 avg=-35519.680000 std=1576.155255
schedule.go 2018/06/01 10:26:09 pop_id=UIe min=-39357.000000 max=-29246.000000 avg=-35797.325000 std=1668.239338
schedule.go 2018/06/01 10:26:09 pop_id=IJN min=-37953.000000 max=-28815.000000 avg=-34964.755000 std=1669.453927
schedule.go 2018/06/01 10:26:09 pop_id=UIe min=-37595.000000 max=-29246.000000 avg=-35396.215000 std=1585.120926
schedule.go 2018/06/01 10:26:09 pop_id=UIe min=-37417.000000 max=-28293.000000 avg=-34983.050000 std=1591.166527
schedule.go 2018/06/01 10:26:09 pop_id=IJN min=-37705.000000 max=-27978.000000 avg=-34526.410000 std=1685.592140
schedule.go 2018/06/01 10:26:09 pop_id=IJN min=-37663.000000 max=-27978.000000 avg=-34086.300000 std=1585.385521
schedule.go 2018/06/01 10:26:09 pop_id=UIe min=-37050.000000 max=-28293.000000 avg=-34562.515000 std=1506.342066
schedule.go 2018/06/01 10:26:10 pop_id=UIe min=-36376.000000 max=-28293.000000 avg=-34127.960000 std=1417.550041
schedule.go 2018/06/01 10:26:10 pop_id=IJN min=-36434.000000 max=-27978.000000 avg=-33659.550000 std=1565.961796
schedule.go 2018/06/01 10:26:10 pop_id=UIe min=-35553.000000 max=-27834.000000 avg=-33776.890000 std=1439.687274
schedule.go 2018/06/01 10:26:10 pop_id=IJN min=-35779.000000 max=-27978.000000 avg=-33276.435000 std=1571.765547

[snip]

schedule.go 2018/06/01 10:26:37 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-13105.810000 std=569.072591
schedule.go 2018/06/01 10:26:37 pop_id=UIe min=-14797.000000 max=-9746.000000 avg=-13208.310000 std=622.588318
schedule.go 2018/06/01 10:26:37 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-13090.395000 std=564.413234
schedule.go 2018/06/01 10:26:37 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-13067.800000 std=570.242484
schedule.go 2018/06/01 10:26:37 pop_id=UIe min=-14797.000000 max=-9746.000000 avg=-13205.330000 std=620.816141
schedule.go 2018/06/01 10:26:38 pop_id=UIe min=-14797.000000 max=-9746.000000 avg=-13187.325000 std=620.124810
schedule.go 2018/06/01 10:26:38 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-13044.520000 std=574.277441
schedule.go 2018/06/01 10:26:38 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-13041.195000 std=569.691186
schedule.go 2018/06/01 10:26:38 pop_id=UIe min=-14797.000000 max=-9746.000000 avg=-13176.480000 std=618.033826
schedule.go 2018/06/01 10:26:38 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-13031.840000 std=566.920034
schedule.go 2018/06/01 10:26:38 pop_id=UIe min=-14797.000000 max=-9746.000000 avg=-13164.640000 std=617.818768
schedule.go 2018/06/01 10:26:38 pop_id=UIe min=-14797.000000 max=-9746.000000 avg=-13132.580000 std=628.239830
schedule.go 2018/06/01 10:26:38 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-13024.580000 std=564.373736
schedule.go 2018/06/01 10:26:38 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-12997.095000 std=570.329112
schedule.go 2018/06/01 10:26:38 pop_id=UIe min=-14797.000000 max=-9746.000000 avg=-13126.275000 std=624.070653
schedule.go 2018/06/01 10:26:38 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-12983.905000 std=583.783818
schedule.go 2018/06/01 10:26:38 pop_id=UIe min=-14797.000000 max=-9746.000000 avg=-13120.270000 std=623.693280
schedule.go 2018/06/01 10:26:38 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-12973.925000 std=579.498947
schedule.go 2018/06/01 10:26:38 pop_id=UIe min=-14797.000000 max=-9746.000000 avg=-13110.700000 std=627.804500
schedule.go 2018/06/01 10:26:38 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-12954.475000 std=586.226440
schedule.go 2018/06/01 10:26:38 pop_id=UIe min=-14797.000000 max=-9746.000000 avg=-13108.250000 std=626.450770
schedule.go 2018/06/01 10:26:38 pop_id=UIe min=-14752.000000 max=-9746.000000 avg=-13091.415000 std=630.471350
schedule.go 2018/06/01 10:26:38 pop_id=IJN min=-14602.000000 max=-10808.000000 avg=-12931.535000 std=578.849565

As you can see, the minimum fitness (with random starting points) started around -42k, and ended around -14k 30 seconds later. Regardless of how I implement the Genome interface, I don't see how this should be possible.

Evaluate against other genome

Hi,
I'm not knowledgeable in the AI/GA domain, and I had an idea in head that confused me.

Now that I sat back, I got it and it's normal, we're trying to optimize a function.

But as I saw it previously, I thought we would evaluate genomes against each other and have the best ones sorted out. But in the current implementation of gago (and in GA in general I guess), the evaluation is against a function, not against another genome.

To explain my idea, an example might help. I have a game with characters that can be created with abilities values (strength, dexterity, constitution) and I would like to know what is the optimum way to dispatch ability point in those abilities to have a good fighter. So I wanted to simulate a fight between 2 genomes to determine a winner as the evaluation. Instead, right now, I just try to optimize ability score because mechanically it will make a better fighter, but it doesn't correspond to the idea I had.

Is this a good idea? Is it applied in other fields/lib? Is it doable already with the current gago?

data race in util_random.go:70

I've got a unit test in my application that detects that a data race when running go test -race with the following output:

WARNING: DATA RACE
Read at 0x00c4202e2000 by goroutine 46:
  math/rand.(*rngSource).Int63()
      /Users/dhuie/src/go/src/math/rand/rng.go:236 +0x3f
  math/rand.(*Rand).Int63()
      /Users/dhuie/src/go/src/math/rand/rand.go:82 +0x51
  github.com/DavidHuie/REDACTED/vendor/github.com/MaxHalford/gago.randString()
      /Users/dhuie/src/github.com/DavidHuie/REDACTED/vendor/github.com/MaxHalford/gago/util_random.go:70 +0x85
  github.com/DavidHuie/REDACTED/vendor/github.com/MaxHalford/gago.(*GA).Initialize.func1()
      /Users/dhuie/src/github.com/DavidHuie/REDACTED/vendor/github.com/MaxHalford/gago/ga.go:100 +0xa8

Gene Uniqueness - PMX/OX

First of all, thank you for all the work on this amazing library!

Now using your predefined crossover functions it seems that if one wants to preserve gene uniqueness one could either use PMX or OX. In my case, however, trying to optimize the order of a set of pointers. Now the issue is that a single pointer can have several occurrences in a gnome, like here:

geneA := "A"
geneB := "B"
geneC := "C"
gnome := []*string {&geneA, &geneA, &geneB, &geneC, &geneC, &geneC}

It seems in cases like this the uniqueness of the number of occurrences is not preserved between crossovers. Is this the intended behavior, as the gnome is not comprised out of unique genes?

Is CrossUniformFloat64 correct?

I was just looking at the source code for CrossUniformFloat64, and I'm a bit puzzled by it. It assigns p1[i] a proportion of each of the old p1[i] and the old p2[i], but then it assigns p2[i] a proportion of each of the new p1[i] and the old p2[i]. Shouldn't it be using some intermediate variables to correctly distribute the parents' values to the children?

Most models do not honor ParallelEval

Problem

Most of the models defined in models.go evaluate the fitness function sequentially, even if ParallelEval is set to true. From what I can tell from inspecting the source code, this applies to ModDownToSize, ModRing, and ModMutationOnly. This poses a problem because SPSO, DiffEvo, and OES all hard-wire ModMutationOnly as their model.

Reproducer

Here's a reproducer:

pareval.zip

Run first with the ModRing stanza commented out then with the ModGenerational stanza commented out and observe the performance difference. Here's what I measured:

ModGenerational

$ time ./pareval 
Best fitness at generation 0: -0.348941
Best fitness at generation 1: -0.757410
Best fitness at generation 2: -0.960569
Best fitness at generation 3: -0.960569
Best fitness at generation 4: -0.968049
Best fitness at generation 5: -0.968049
Best fitness at generation 6: -0.968049
Best fitness at generation 7: -0.968049
Best fitness at generation 8: -0.968049
Best fitness at generation 9: -0.983219
Best fitness at generation 10: -0.999640

real	0m42.007s
user	0m0.014s
sys	0m0.000s

ModRing

$ time ./pareval 
Best fitness at generation 0: -0.522594
Best fitness at generation 1: -0.928452
Best fitness at generation 2: -0.928452
Best fitness at generation 3: -0.928452
Best fitness at generation 4: -0.935102
Best fitness at generation 5: -0.935497
Best fitness at generation 6: -0.996757
Best fitness at generation 7: -0.996757
Best fitness at generation 8: -0.996757
Best fitness at generation 9: -0.996757
Best fitness at generation 10: -0.998831

real	7m32.042s
user	0m0.050s
sys	0m0.033s

Resolution

Unfortunately, this may be a difficult problem to fix. As far as I can tell, a Model has no access to a GAConfig and therefore can't determine if ParallelEval is set to true or false. If nothing else, others can reference this issue if, like I, they find that SPSO, DiffEvo, and OES run substantially slower than GA when given a computationally intense fitness function.

NOffsprings has to higher than 0

The unsigned int mod.NOffsprings can be never negative hence here is a logic bug.

if mod.NOffsprings <= 0 {
   return errors.New("NOffsprings has to higher than 0")
}

Could this not just be a int as uint normally used in Go just for binary operations?

models.go:217

// Validate ModDownToSize fields.
func (mod ModDownToSize) Validate() error {
	// Check the number of offsprings value
	if mod.NOffsprings <= 0 {
		return errors.New("NOffsprings has to higher than 0")
	}
	// Check the first selection method presence
	if mod.SelectorA == nil {
		return errNilSelector
	}
	// Check the first selection method parameters
	var errSelectorA = mod.SelectorA.Validate()
	if errSelectorA != nil {
		return errSelectorA
	}
	// Check the second selection method presence
	if mod.SelectorB == nil {
		return errNilSelector
	}
	// Check the second selection method parameters
	var errSelectorB = mod.SelectorB.Validate()
	if errSelectorB != nil {
		return errSelectorB
	}
	// Check the mutation rate in the presence of a mutator
	if mod.MutRate < 0 || mod.MutRate > 1 {
		return errInvalidMutRate
	}
	return nil
}

Tests are failing

bash-3.2$ go test ./...
--- FAIL: ExampleDiffEvo (0.00s)
got:
Found minimum of 0.00137 in [0.00044201296938241373 0.00019592462513264675]
want:
Found minimum of 0.00137 in [0.0004420129693826938 0.000195924625132926]
--- FAIL: ExampleOES (0.00s)
got:
Found minimum of 0.02270 in [0.006807861794722089 -0.008251984117745251]
want:
Found minimum of 0.02270 in [0.006807861794722094 -0.008251984117745246]
FAIL
FAIL	github.com/MaxHalford/eaopt	0.140s
FAIL
bash-3.2$ git show
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
commit acd0f5778f8e7eca8524d53cb9b236cecb67e7ba (HEAD -> master, origin/master, origin/HEAD)
Merge: 3581619 6da0af6
Author: Max Halford <[email protected]>
Date:   Mon Apr 5 11:12:42 2021 +0200

    Merge pull request #52 from spakin/master

bash-3.2$

Looks like the precision is a little off in the assertion.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.