func TestMutate(t *testing.T) { // all possible mutations mutset := map[string]bool{ "(9 + 4)": false, "((9 + 4) + sqr(y))": false, "(sqr((9 + 4)) + sqr(y))": false, "(sqr(x) + (9 + 4))": false, "(sqr(x) + sqr((9 + 4)))": false, } pset := initPset(true) exprs := testExprs(pset) before := gp.Individual{Code: exprs[1]} add := exprs[0] gen := genProxy{add} t.Log("mutate: ", before.Code, "plus", gen.Generate().Code) mut := gp.MutUniform(gen) gp.SetSeed(1) for i := 0; i < 10; i++ { after := mut.Variate(gp.Population{before.Clone()}) t.Log("becomes:", after[0]) text := after[0].Code.Format() if _, ok := mutset[text]; ok { mutset[text] = true } else { t.Error("unexpected mutation", text) } } for key, ok := range mutset { if !ok { t.Error("missing mutation", key) } } }
func Example_gp() { // create initial population gp.SetSeed(1) pset := gp.CreatePrimSet(1, "x") pset.Add(num.Add, num.Sub, num.Mul, num.Div, num.Neg, num.V(0), num.V(1)) generator := gp.GenFull(pset, 1, 3) pop, evals := gp.CreatePopulation(500, generator).Evaluate(eval{}, 1) best := pop.Best() fmt.Printf("gen=%d evals=%d fit=%.4f\n", 0, evals, best.Fitness) // setup genetic variations tournament := gp.Tournament(3) mutate := gp.MutUniform(gp.GenGrow(pset, 0, 2)) crossover := gp.CxOnePoint() // loop till reach target fitness or exceed no. of generations for gen := 1; gen <= 40 && best.Fitness < 1; gen++ { offspring := tournament.Select(pop, len(pop)) pop, evals = gp.VarAnd(offspring, crossover, mutate, 0.5, 0.2).Evaluate(eval{}, 1) best = pop.Best() fmt.Printf("gen=%d evals=%d fit=%.4f\n", gen, evals, best.Fitness) } fmt.Println(best.Code.Format()) // Output: // set random seed: 1 // gen=0 evals=500 fit=0.1203 // gen=1 evals=299 fit=0.3299 // gen=2 evals=286 fit=0.6633 // gen=3 evals=265 fit=0.6633 // gen=4 evals=280 fit=0.6633 // gen=5 evals=291 fit=0.6633 // gen=6 evals=302 fit=0.6633 // gen=7 evals=294 fit=1.0000 // (x + (((x / 1) - ((x / 1) * -(((x * x) + x)))) * (1 * x))) }
func ExampleModel() { gp.SetSeed(1) pset := gp.CreatePrimSet(1, "x") pset.Add(num.Add, num.Sub, num.Mul, num.Div, num.Neg, num.V(0), num.V(1)) problem := gp.Model{ PrimitiveSet: pset, Generator: gp.GenFull(pset, 1, 3), PopSize: 500, Fitness: getFitness, Offspring: gp.Tournament(3), Mutate: gp.MutUniform(gp.GenGrow(pset, 0, 2)), MutateProb: 0.2, Crossover: gp.CxOnePoint(), CrossoverProb: 0.5, Threads: 1, } logger := &stats.Logger{MaxGen: 20, TargetFitness: 0.99, PrintStats: true} problem.Run(logger) // Output: // set random seed: 1 // Gen Evals FitMax FitAvg FitStd SizeAvg SizeMax DepthAvg DepthMax // 0 500 0.12 0.025 0.014 6.85 15 1.96 3 // 1 299 0.33 0.0344 0.0204 6.33 27 1.93 6 // 2 286 0.663 0.0469 0.0448 6.26 27 1.9 7 // 3 265 0.663 0.0598 0.0683 6.58 34 2.06 9 // 4 280 0.663 0.0772 0.088 7.51 39 2.39 9 // 5 291 0.663 0.0918 0.1 8.92 32 2.82 8 // 6 302 0.663 0.117 0.133 10.3 35 3.2 10 // 7 294 1 0.152 0.17 11.1 35 3.48 10 // ** SUCCESS ** }
// test generating random individuals func TestGenerate(t *testing.T) { pset := initPset(false) pset.Add(V(0), V(1)) gen := gp.GenRamped(pset, 1, 3) gp.SetSeed(0) for i := 0; i < 10; i++ { ind := gen.Generate() res := ind.Code.Eval(V(6), V(7)) t.Log(ind.Code, ind.Code.Format(), "(6,7) =>", res) } }
// test evaluating some simple expressions func TestEval(t *testing.T) { pset := initPset(true) exprs := testExprs(pset) expect := []V{13, 25, 10.5, 0, 6} gp.SetSeed(1) for i, expect := range expect { val := exprs[i].Eval(V(3), V(4)) t.Log(exprs[i], "(3,4) ", exprs[i].Format(), " => ", val) if val != expect { t.Errorf("Eval(%s) = %f", exprs[i], val) } } }
// test graphviz functions func TestGraph(t *testing.T) { gp.SetSeed(1) pset := initPset(true) exprs := testExprs(pset) t.Log(exprs[2], exprs[2].Format()) graph := exprs[2].Graph("test") t.Log(graph) data, err := gp.Layout(graph, "svg") if err != nil { t.Error(err) } t.Log(string(data)) }
// test ephemeral random constants func TestEphemeral(t *testing.T) { pset := initPset(false) erc := Ephemeral("ERC", func() V { return V(rand.Intn(10)) }) pset.Add(erc, erc, erc) gen := gp.GenFull(pset, 1, 3) gp.SetSeed(2) ind := gen.Generate() t.Log(ind.Code, ind.Code.Format()) val := ind.Code.Eval(V(6), V(7)) t.Log("evals to", val, "for x=6 y=7") if val != V(16) { t.Errorf("Eval(%s) = %f", ind.Code, val) } }
// ParseFlags reads command flags and sets no. of threads and random seed. func ParseFlags(opts *Options) { flag.IntVar(&opts.MaxGen, "gens", opts.MaxGen, "maximum no. of generations") flag.IntVar(&opts.TournSize, "tournsize", opts.TournSize, "tournament size") flag.IntVar(&opts.PopSize, "popsize", opts.PopSize, "population size") flag.IntVar(&opts.Threads, "threads", opts.Threads, "number of parallel threads") flag.Int64Var(&opts.Seed, "seed", opts.Seed, "random seed - set randomly if <= 0") flag.Float64Var(&opts.TargetFitness, "target", opts.TargetFitness, "target fitness") flag.Float64Var(&opts.CrossoverProb, "cxprob", opts.CrossoverProb, "crossover probability") flag.Float64Var(&opts.MutateProb, "mutprob", opts.MutateProb, "mutation probability") flag.BoolVar(&opts.Plot, "plot", opts.Plot, "serve plot data via http") flag.BoolVar(&opts.Verbose, "v", opts.Verbose, "print out best individual so far") flag.Parse() gp.SetSeed(opts.Seed) runtime.GOMAXPROCS(opts.Threads) }
// test generating population and calculating stats func TestStats(t *testing.T) { gp.SetSeed(1) s := getStats(t, 0) if fmt.Sprint(s) != exp { t.Error("stats text looks wrong! Expected\n", exp) } for _, fld := range fields { val, err := s.Get(fld) if err != nil { t.Error(err) } t.Log(fld, "=>", val) } _, err := s.Get("Fit.Foo") if fmt.Sprint(err) != "Stats field Foo is not valid" { t.Error("expected error for missing field") } }