// Generates the initial population func generateFirst(ctx neat.Context, cfg ClassicSettings) (next neat.Population, err error) { // Create the first generation next = neat.Population{ Generation: 0, Species: make([]neat.Species, 1, 10), Genomes: make([]neat.Genome, cfg.PopulationSize()), } // Create the genomes wg := new(sync.WaitGroup) for i := 0; i < len(next.Genomes); i++ { wg.Add(1) go func(i int) { genome := createSeed(ctx, cfg) genome.ID = ctx.NextID() genome.SpeciesIdx = 0 next.Genomes[i] = genome wg.Done() }(i) } wg.Wait() // Create the initial species next.Species[0] = neat.Species{Example: next.Genomes[0]} return }
func (a *File) Restore(ctx neat.Context) error { // Restore the settings name := a.makePath("config") f, err := os.Open(name) if err != nil { return err } d := json.NewDecoder(f) if err = d.Decode(&ctx); err != nil { f.Close() return err } f.Close() // Restore the state values for k, v := range ctx.State() { name := a.makePath(k) if _, err := os.Stat(name); os.IsNotExist(err) { continue } f, err = os.Open(name) if err != nil { return err } d = json.NewDecoder(f) if err = d.Decode(&v); err != nil { f.Close() return err } f.Close() } return nil }
func (s *Novelty) SetContext(x neat.Context) error { x.State()["novelty-behaviors"] = &s.behaviors if cx, ok := s.Searcher.(neat.Contextable); ok { return cx.SetContext(x) } return nil }
func (a *File) Archive(ctx neat.Context) error { // Save the settings name := a.makePath("config") var dir = path.Dir(name) if _, err := os.Stat(dir); err != nil { if os.IsNotExist(err) { os.MkdirAll(dir, os.ModePerm) } else { // other error } } f, err := os.Create(name) if err != nil { panic(err) return err } b, err := json.MarshalIndent(ctx, "", " ") if err != nil { f.Close() return err } f.Write(b) f.Close() // Save the state values for k, v := range ctx.State() { name := a.makePath(k) f, err = os.Create(name) if err != nil { return err } b, err := json.MarshalIndent(v, "", " ") if err != nil { f.Close() return err } f.Write(b) f.Close() } return nil }
func (v *Web) SetContext(x neat.Context) error { v.ctx = x x.State()["web-fitness"] = &v.fitness x.State()["web-complexity"] = &v.complexity x.State()["web-species"] = &v.species x.State()["web-best"] = &v.best return nil }
// Returns a genome build from the parameters func createSeed(ctx neat.Context, cfg ClassicSettings) (adam neat.Genome) { // Create the genome inputs := cfg.NumInputs() outputs := cfg.NumOutputs() adam = neat.Genome{ Nodes: make(map[int]neat.Node, 1+inputs+outputs), } nodes := make([]neat.Node, len(adam.Nodes)) node := neat.Node{NeuronType: neat.Bias, ActivationType: neat.Direct, X: 0, Y: 0} node.Innovation = ctx.Innovation(neat.NodeInnovation, node.Key()) adam.Nodes[node.Innovation] = node nodes = append(nodes, node) for i := 0; i < inputs; i++ { node = neat.Node{NeuronType: neat.Input, ActivationType: neat.Direct, X: float64(i+1) / float64(inputs), Y: 0} node.Innovation = ctx.Innovation(neat.NodeInnovation, node.Key()) adam.Nodes[node.Innovation] = node nodes = append(nodes, node) } x := 0.5 for i := 0; i < outputs; i++ { if outputs > 1 { x = float64(i) / float64(outputs-1) } node = neat.Node{NeuronType: neat.Output, ActivationType: cfg.OutputActivation(), X: x, Y: 1} node.Innovation = ctx.Innovation(neat.NodeInnovation, node.Key()) adam.Nodes[node.Innovation] = node nodes = append(nodes, node) } rng := rand.New(rand.NewSource(rand.Int63())) // adam.Conns = make(map[int]neat.Connection, (1+inputs)*outputs) // for i := 0; i < 1+inputs; i++ { // for j := 0; j < outputs; j++ { // w := (rng.Float64()*2.0 - 1.0) * cfg.WeightRange() // conn := neat.Connection{Source: nodes[i].Innovation, Target: nodes[j+1+inputs].Innovation, Enabled: true, Weight: w} // conn.Innovation = ctx.Innovation(neat.ConnInnovation, conn.Key()) // adam.Conns[conn.Innovation] = conn // } // } ts := cfg.Traits() adam.Traits = make([]float64, len(ts)) for i, trait := range ts { adam.Traits[i] = rng.Float64()*(trait.Max-trait.Min) + trait.Min // TODO: Get setting values from configuration } return adam }
func createOffspring(ctx neat.Context, cfg ClassicSettings, cross bool, rng *rand.Rand, pool map[int]Improvements, cnts map[int]int, next *neat.Population) (err error) { var child neat.Genome for idx, cnt := range cnts { l := pool[idx] for i := 0; i < cnt; i++ { p1, p2 := pickParents(cfg, cross, rng, l, pool) if p1.ID == p2.ID { child = neat.CopyGenome(p1) } else { child, err = ctx.Crosser().Cross(p1, p2) if err != nil { return } } child.ID = ctx.NextID() child.Birth = next.Generation err = ctx.Mutator().Mutate(&child) next.Genomes = append(next.Genomes, child) } } return }
func NewExperiment(ctx neat.Context, cfg neat.ExperimentSettings, t int) (exp *neat.Experiment, err error) { // Create the experiment exp = &neat.Experiment{ExperimentSettings: cfg} exp.SetContext(ctx) // Restore the saved setting and, if available, state if *ConfigName == "" { *ConfigName = os.Args[0] // Use the executable's name } rst := &archiver.File{ FileSettings: ConfigSettings{path: *ConfigPath, name: *ConfigName}, } if err = rst.Restore(ctx); err != nil { return } // Update helpers with trial number if t > NoTrials { hs := []interface{}{ ctx.Archiver(), ctx.Comparer(), ctx.Crosser(), ctx.Decoder(), ctx.Evaluator(), ctx.Generator(), ctx.Mutator(), ctx.Searcher(), ctx.Speciater(), ctx.Visualizer(), } for _, h := range hs { if th, ok := h.(neat.Trialable); ok { th.SetTrial(t) } } } // Load ids and innovations if ph, ok := ctx.(neat.Populatable); ok { ph.SetPopulation(exp.Population()) } return }