func makeMultiMutation(s *base.Settings, multiMut, enbSin, enbNod, enbSub, enbAre, enbLsubt, enbLoc bool) func(float64, *base.Individual) bool { // La mutazione a che profondità avviene? // Quanto è profondo l'albero che vado a generare? // Quanto è profondo l'albero che vado a sostituire? // Separare foglie e nodi countInt := func(name string, v int) { if _, ok := s.IntCounters[name]; !ok { s.IntCounters[name] = new(counter.IntCounter) } s.IntCounters[name].Count(v) } countBool := func(name string, v bool) { if _, ok := s.Counters[name]; !ok { s.Counters[name] = new(counter.BoolCounter) } s.Counters[name].Count(v) } statFuncSin := func(nDepth, replDepth int, isLeaf bool) { countInt(mut_single_node_depth, nDepth) countInt(mut_single_node_repld, replDepth) countBool(mut_single_node_leaves, isLeaf) } statFuncNod := func(nDepth, replDepth int, isLeaf bool) { countInt(mut_multi_node_depth, nDepth) countInt(mut_multi_node_repld, replDepth) countBool(mut_multi_node_leaves, isLeaf) } statFuncTree := func(nDepth, replDepth int, isLeaf bool) { countInt(mut_tree_node_depth, nDepth) countInt(mut_tree_node_repld, replDepth) countBool(mut_tree_node_leaves, isLeaf) } statFuncArea := func(nDepth, replDepth int, isLeaf bool) { countInt(mut_area_node_depth, nDepth) countInt(mut_area_node_repld, replDepth) countBool(mut_area_node_leaves, isLeaf) } statFuncLevSubtr := func(nDepth, replDepth int, isLeaf bool) { countInt(mut_lsubt_node_depth, nDepth) countInt(mut_lsubt_node_repld, replDepth) countBool(mut_lsubt_node_leaves, isLeaf) } singleMut := node.MakeTreeSingleMutation(s.Functionals, s.Terminals, statFuncSin) // func(*Node) nodeMut := node.MakeTreeNodeMutation(s.Functionals, s.Terminals, statFuncNod) // funcs, terms []gp.Primitive)// func(*Node) int { subtrMut := node.MakeSubtreeMutation(s.MaxDepth, s.GenFunc, statFuncTree) areaMut := node.MakeSubtreeMutationGuided(s.MaxDepth, s.GenFunc, node.ArityDepthProbComputer, statFuncArea) subtLevelMut := node.MakeSubtreeMutationGuided(s.MaxDepth, s.GenFunc, node.UniformDepthProbComputer, statFuncLevSubtr) const neighbSize = 5 // Neighborhood size for local search return func(pMut float64, ind *base.Individual) bool { perm := rand.Perm(6) // Randomly permutate the algorithms to pick evCount := 0 // Number of events (mutations performed) for _, v := range perm { event := rand.Float64() < pMut // Perform mutation? switch v { case 0: if enbSin { ind.CountEvent(mut_single_event, event) if event { evCount++ fit := ind.Evaluate() singleMut(ind.Node) newFit := ind.Evaluate() ind.CountEvent(mut_single_improv, s.BetterThan(newFit, fit)) } if !multiMut { return event } } case 1: if enbNod { fit := ind.Evaluate() event = nodeMut(pMut, ind.Node) != 0 ind.CountEvent(mut_multi_event, event) if event { evCount++ newFit := ind.Evaluate() ind.CountEvent(mut_multi_improv, s.BetterThan(newFit, fit)) } if !multiMut { return event } } case 2: if enbSub { ind.CountEvent(mut_tree_event, event) if event { evCount++ fit := ind.Evaluate() subtrMut(ind.Node) newFit := ind.Evaluate() ind.CountEvent(mut_tree_improv, s.BetterThan(newFit, fit)) } if !multiMut { return event } } case 3: if enbAre { ind.CountEvent(mut_area_event, event) if event { evCount++ fit := ind.Evaluate() areaMut(ind.Node) newFit := ind.Evaluate() ind.CountEvent(mut_area_improv, s.BetterThan(newFit, fit)) } if !multiMut { return event } } case 4: if enbLsubt { ind.CountEvent(mut_lsubt_event, event) if event { evCount++ fit := ind.Evaluate() subtLevelMut(ind.Node) newFit := ind.Evaluate() ind.CountEvent(mut_lsubt_improv, s.BetterThan(newFit, fit)) } if !multiMut { return event } } default: if enbLoc { // Local search ind.CountEvent(mut_local_event, event) if event { evCount++ fit := ind.Evaluate() for i := 0; i < neighbSize; i++ { mutated := ind.Copy().(*base.Individual) // Copy individual singleMut(mutated.Node) // Apply mutation if s.BetterThan(mutated.Fitness(), ind.Fitness()) { // If improved, save the individual ind.Node = mutated.Node // Invalidate! ind.Invalidate() } } // Perform singleMut K times newFit := ind.Evaluate() ind.CountEvent(mut_local_improv, s.BetterThan(newFit, fit)) } if !multiMut { return event } } } // In the case we don't execute anything, go to the next method } // If this happens, all the mutations were disabled, or all the mutations // were performed when multi mutation was enabled if multiMut { countInt(mut_count_multi, evCount) } return evCount > 0 } }
func Evolve(calcMaxDepth func(*imgut.Image) int, fun, ter []gp.Primitive, drawfun func(*base.Individual, *imgut.Image)) { startTime := time.Now() // Setup options fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError) numGen := fs.Int("g", 100, "Number of generations") popSize := fs.Int("p", 1000, "Size of population") saveInterval := fs.Int("n", 25, "Generations interval between two snapshot saves") tournSize := fs.Int("T", 3, "Tournament size") pCross := fs.Float64("C", 0.8, "Crossover probability") pMut := fs.Float64("M", 0.1, "Bit mutation probability") quiet := fs.Bool("q", false, "Quiet mode") fElite := fs.Bool("el", false, "Enable elite individual") fInitFull := fs.Bool("full", true, "Enable full initialization") fInitGrow := fs.Bool("grow", true, "Enable grow initialization") fInitRamped := fs.Bool("ramp", true, "Enable ramped initialization") fMutSin := fs.Bool("ms", false, "Enable Single Mutation") fMutNod := fs.Bool("mn", false, "Enable Node Mutation") fMutSub := fs.Bool("mt", false, "Enable Subtree Mutation") fMutAre := fs.Bool("ma", false, "Enable Area Mutation") fMutLsubt := fs.Bool("mlt", false, "Enable Level-Subtree Mutation") fMutLoc := fs.Bool("ml", false, "Enable Local Mutation") fSelect := fs.String("sel", "torun", "Pick selection method (tourn, rmad, irmad)") fMultiMut := fs.Bool("mM", false, "Enable multiple mutations") fFitness := fs.String("fit", "rmse", "Pick fitness function (rmse, mse, rmsed, ssim)") //advStats := fs.Bool("stats", false, "Enable advanced statistics") //nps := fs.Bool("nps", false, "Disable population snapshot (no-pop-snap)") targetPath := fs.String("t", "", "Target image (PNG) path") var basedir, basename string cpuProfile := fs.String("cpuprofile", "", "Write CPU profile to file") fs.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) fs.PrintDefaults() fmt.Fprintf(os.Stderr, " basedir (string) to be used for saving logs and files\n") fmt.Fprintf(os.Stderr, " basename (string) to be used for saving logs and files\n") } fs.Parse(os.Args[1:]) // Check if the argument args := fs.Args() if len(args) != 2 { fs.Usage() fmt.Fprintf(os.Stderr, "\nBasename/basedir parameter not specified\n") return } else { basedir = args[0] basename = args[1] } sta := stats.Create(basedir, basename) // Build settings var settings base.Settings // Primitives to use settings.Functionals = fun settings.Terminals = ter // Draw function to use settings.Draw = drawfun settings.Ramped = *fInitRamped if settings.Ramped { fmt.Println("Using ramped initialization") } // Pick initialization method based on flags var genFuncBit func(minH, maxH int, funcs, terms []gp.Primitive) *node.Node if *fInitFull && !*fInitGrow { fmt.Println("Using init strategy: full") genFuncBit = node.MakeTreeFull // Initialize tree using full } else if !*fInitFull && *fInitGrow { fmt.Println("Using init strategy: balanced grow") genFuncBit = node.MakeTreeGrowBalanced // Initialize using grow } else { fmt.Println("Using init strategy: half-and-half") genFuncBit = node.MakeTreeHalfAndHalf // Initialize using both (half and half) } settings.GenFunc = func(maxDep int) *node.Node { t := genFuncBit(0, maxDep, fun, ter) // /* TODO */ sistemare la minH s := settings if _, ok := s.IntCounters[tree_init_depth]; !ok { s.IntCounters[tree_init_depth] = new(counter.IntCounter) } s.IntCounters[tree_init_depth].Count(node.Depth(t)) return t } // Build statistic map settings.Statistics = make(map[string]*sequence.SequenceStats) settings.Counters = make(map[string]*counter.BoolCounter) settings.IntCounters = make(map[string]*counter.IntCounter) // Names of extra statistics statsKeys := []string{} countersKeys := []string{} intCountersKeys := []string{} intCountersKeys = append(intCountersKeys, tree_init_depth) if *fMutSin { countersKeys = append(countersKeys, mut_single_event, mut_single_improv, mut_single_node_leaves) intCountersKeys = append(intCountersKeys, mut_single_node_depth, mut_single_node_repld) } if *fMutNod { countersKeys = append(countersKeys, mut_multi_event, mut_multi_improv, mut_multi_node_leaves) intCountersKeys = append(intCountersKeys, mut_multi_node_depth, mut_multi_node_repld) } if *fMutSub { countersKeys = append(countersKeys, mut_tree_event, mut_tree_improv, mut_tree_node_leaves) intCountersKeys = append(intCountersKeys, mut_tree_node_depth, mut_tree_node_repld) } if *fMutAre { countersKeys = append(countersKeys, mut_area_event, mut_area_improv, mut_area_node_leaves) intCountersKeys = append(intCountersKeys, mut_area_node_depth, mut_area_node_repld) } if *fMutLsubt { countersKeys = append(countersKeys, mut_lsubt_event, mut_lsubt_improv, mut_lsubt_improv) intCountersKeys = append(intCountersKeys, mut_lsubt_node_depth, mut_lsubt_node_repld) } if *fMutLoc { countersKeys = append(countersKeys, mut_local_event, mut_local_improv) // intCountersKeys = append(intCountersKeys, "mut_local_") TODO } if *fMultiMut { intCountersKeys = append(intCountersKeys, mut_count_multi) } if *cpuProfile != "" { f, err := os.Create(*cpuProfile) if err != nil { fmt.Println("ERROR", err) panic("Cannot create cpuprofile") } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } // Load the target var err error settings.ImgTarget, err = imgut.Load(*targetPath) if err != nil { fmt.Fprintln(os.Stderr, "ERROR: Cannot load image", *targetPath) panic("Cannot load image") } if !*quiet { fmt.Println("Image format RGB?", settings.ImgTarget.ColorSpace == imgut.MODE_RGB, settings.ImgTarget.ColorSpace) } // Compute the right value of maxDepth settings.MaxDepth = calcMaxDepth(settings.ImgTarget) if !*quiet { fmt.Println("For area of", settings.ImgTarget.W*settings.ImgTarget.H, "pixels, max depth is", settings.MaxDepth) } // Create temporary surface, of same size and mode //settings.ImgTemp = imgut.Create(settings.ImgTarget.W, settings.ImgTarget.H, settings.ImgTarget.ColorSpace) // Create temporary surface for the entire population pImgCols := int(math.Ceil(math.Sqrt(float64(*popSize)))) pImgRows := int(math.Ceil(float64(*popSize) / float64(pImgCols))) imgTempPop := imgut.Create(pImgCols*settings.ImgTarget.W, pImgRows*settings.ImgTarget.H, settings.ImgTarget.ColorSpace) // Define the operators settings.CrossOver = makeCrossover(&settings) settings.Mutate = makeMultiMutation(&settings, *fMultiMut, *fMutSin, *fMutNod, *fMutSub, *fMutAre, *fMutLsubt, *fMutLoc) // Fitness if *fFitness == "mse" { settings.FitFunc = base.MakeFitMSE(settings.ImgTarget) } else if *fFitness == "rmsed" { statsKeys = append(statsKeys, "fit-delta-rmse") settings.FitFunc = base.MakeFitEdge(settings.ImgTarget, settings.Statistics) } else if *fFitness == "ssim" { settings.FitFunc = base.MakeFitSSIM(settings.ImgTarget) } else { statsKeys = append(statsKeys, "fit-delta-rmse") settings.FitFunc = base.MakeFitRMSE(settings.ImgTarget) } // Selection ts := *tournSize if *fSelect == "rmad" { settings.Select = base.MakeSelectRMAD(ts, ts*ts, settings.BetterThan) } else if *fSelect == "irmad" { settings.Select = base.MakeSelectIRMAD(ts, ts*ts, settings.BetterThan) } else { settings.Select = base.MakeSelectTourn(ts, settings.BetterThan) } // Seed rng if !*quiet { fmt.Println("Number of CPUs", runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU()) fmt.Println("CPUs limits", runtime.GOMAXPROCS(0)) } // Build population pop := new(base.Population) pop.Set = &settings //pop.TournSize = *tournSize pop.Initialize(*popSize) // Save initial population FIXME it's for debugging /* for i := range pop.Pop { pop.Pop[i].Draw(imgTemp) imgTemp.WritePNG(fmt.Sprintf("pop_ind_%v.png", i)) } */ // Number of parallel generators to setup pipelineSize := 1 // Was 4 FIXME but there are statistics used in parallel and not ready for concurrent access // Containers for pipelined operators chXo := make([]<-chan ga.PipelineIndividual, pipelineSize) chMut := make([]<-chan ga.PipelineIndividual, pipelineSize) // Save best individual, for elitism var elite ga.Individual = nil // Save time before starting //genTime := time.Now() // Loop until max number of generation is reached for g := 0; g < *numGen; g++ { // Compute fitness for every individual with no fitness fitnessEval := pop.Evaluate() fitnessEval = fitnessEval // //if !*quiet { // fmt.Println("Generation ", g, "fit evals", fitnessEval, time.Since(genTime)) // genTime = time.Now() //} // Compute various statistics sta.Observe(pop) // Statistics and samples if g%*saveInterval == 0 { snapName, snapPopName := sta.SaveSnapshot(pop, *quiet, countersKeys, statsKeys, intCountersKeys) // Save best individual if false { pop.BestIndividual().Fitness() pop.BestIndividual().(*base.Individual).ImgTemp.WritePNG(snapName) } // Save best individual code // pop.BestIndividual().(*base.Individual).Draw(settings.ImgTemp) // settings.ImgTemp.WritePNG(snapName) // Save pop images pop.Draw(imgTempPop, pImgCols, pImgRows) imgTempPop.WritePNG(snapPopName) } // Setup parallel pipeline selectionSize := len(pop.Pop) // int(float64(len(pop.Pop))*0.3)) if you want to randomly generate new individuals chSel := ga.GenSelect(pop, selectionSize, float32(g)/float32(*numGen), elite) for i := 0; i < pipelineSize; i++ { chXo[i] = ga.GenCrossover(chSel, *pCross) chMut[i] = ga.GenMutate(chXo[i], *pMut) } var sel []ga.PipelineIndividual = ga.Collector(ga.FanIn(chMut...), selectionSize) // Replace old population and compute statistics for i := range sel { pop.Pop[i] = sel[i].Ind.(*base.Individual) sta.ObserveCrossoverFitness(sel[i].CrossoverFitness, sel[i].InitialFitness) sta.ObserveMutationFitness(sel[i].MutationFitness, sel[i].CrossoverFitness) } // When elitism is activated, get best individual if *fElite { elite = pop.BestIndividual() } // Build new individuals //base.RampedFill(pop, len(sel), len(pop.Pop)) } fitnessEval := pop.Evaluate() fitnessEval = fitnessEval // Population statistics sta.Observe(pop) //if !*quiet { // fmt.Println("Generation", *numGen, "fit evals", fitnessEval) // fmt.Println("Best individual", pop.BestIndividual()) //} snapName, snapPopName := sta.SaveSnapshot(pop, *quiet, countersKeys, statsKeys, intCountersKeys) // Save best individual if false { pop.BestIndividual().Fitness() pop.BestIndividual().(*base.Individual).ImgTemp.WritePNG(snapName) } // pop.BestIndividual().(*base.Individual).Draw(settings.ImgTemp) // settings.ImgTemp.WritePNG(snapName) // Save pop images pop.Draw(imgTempPop, pImgCols, pImgRows) imgTempPop.WritePNG(snapPopName) if !*quiet { fmt.Println("Best individual:") fmt.Println(pop.BestIndividual()) } elapsedTime := time.Since(startTime) fmt.Println("Execution took %s", elapsedTime) /* bestName := fmt.Sprintf("%v/best/%v.png", basedir, basename) if !*quiet { fmt.Println("Saving best individual in", bestName) fmt.Println(pop.BestIndividual()) } pop.BestIndividual().(*base.Individual).Draw(settings.ImgTemp) settings.ImgTemp.WritePNG(bestName) */ }