├── README.md ├── curve_fit_test.go ├── interfaces.go ├── curve_fit_run.go └── curve_fit.go /README.md: -------------------------------------------------------------------------------- 1 | ### Genetic Programming 2 | -------------------------------------------------------------------------------- /curve_fit_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestCanRun(t *testing.T) { 8 | } 9 | -------------------------------------------------------------------------------- /interfaces.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Gene interface { 4 | Score() float32 5 | Mix(*Gene) Gene 6 | Swap(*Gene) Gene 7 | Mutate() Gene 8 | } 9 | 10 | type Genes []Gene 11 | 12 | type GenePool interface { 13 | Generate() 14 | Select() 15 | Mutate() 16 | Best() 17 | } 18 | -------------------------------------------------------------------------------- /curve_fit_run.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "sort" 7 | ) 8 | 9 | // Create a bunch of random genes 10 | func Seed(n int) CurveFitGenes { 11 | results := make(CurveFitGenes, n) 12 | for i := 0; i < n; i++ { 13 | results[i] = RandomCurveFitGene() 14 | } 15 | return results 16 | } 17 | 18 | type CurveFitGenePool struct { 19 | genes CurveFitGenes 20 | } 21 | 22 | // SEED!! 23 | func (s *CurveFitGenePool) Generate(n int) { 24 | s.genes = make(CurveFitGenes, n) 25 | for i := 0; i < n; i++ { 26 | s.genes[i] = RandomCurveFitGene() 27 | } 28 | } 29 | 30 | func ScaleDown(n int, percent float64) int { 31 | return int(float64(n) * percent) 32 | } 33 | 34 | // CROSSOVER!! 35 | func (s *CurveFitGenePool) CrossOver() { 36 | sort.Sort(s.genes) 37 | 38 | results := make(CurveFitGenes, 0) 39 | 40 | size := len(s.genes) 41 | 42 | TOP_SIZE := ScaleDown(size, 0.2) 43 | MIX_SIZE := ScaleDown(size, 0.3) 44 | RND_SIZE := ScaleDown(size, 0.3) 45 | 46 | // Keep some number of top 47 | for i := 0; i < TOP_SIZE; i++ { 48 | results = append(results, s.genes[i]) 49 | } 50 | 51 | // Mix top with top 52 | for i := 0; i < MIX_SIZE; i++ { 53 | h := results[rand.Int()%TOP_SIZE] 54 | results = append( 55 | results, 56 | s.genes[i].Mix(&h), 57 | ) 58 | } 59 | 60 | // Mutate some of the bottom 61 | for i := 0; i < size-TOP_SIZE-MIX_SIZE-RND_SIZE; i++ { 62 | h := s.genes[i] 63 | results = append( 64 | results, 65 | h.Mutate(), 66 | ) 67 | } 68 | 69 | // Add 20 random ones in 70 | for i := 0; i < RND_SIZE; i++ { 71 | results = append( 72 | results, 73 | RandomCurveFitGene(), 74 | ) 75 | } 76 | 77 | // Replace old generation with the current one 78 | s.genes = results 79 | } 80 | 81 | // MUTATE!! 82 | func (s *CurveFitGenePool) Mutate() { 83 | for i, v := range s.genes { 84 | if i%2 == 0 { 85 | v.Mutate() 86 | } 87 | } 88 | } 89 | 90 | // Return Best Gene 91 | func (s *CurveFitGenePool) Best() CurveFitGene { 92 | return s.genes[0] 93 | } 94 | 95 | // MAIN 96 | func main() { 97 | genes := CurveFitGenePool{[]CurveFitGene{}} 98 | genes.Generate(667) 99 | 100 | for i := 0; i < 1000; i++ { 101 | genes.CrossOver() 102 | genes.Mutate() 103 | } 104 | 105 | b := genes.Best() 106 | fmt.Println(b, b.Score()) 107 | } 108 | -------------------------------------------------------------------------------- /curve_fit.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "math/rand" 7 | "sort" 8 | ) 9 | 10 | func xxx() { 11 | fmt.Println("x_x") 12 | } 13 | 14 | // Gene encoding of the curve-fitter 15 | type CurveFitGene struct { 16 | A, B, C float64 17 | } 18 | 19 | // Just a simpler way to say a slice of genes 20 | type CurveFitGenes []CurveFitGene 21 | 22 | /** 23 | * Sortable 24 | * Sortable 25 | * Sortable 26 | */ 27 | 28 | // Return length of 29 | func (s CurveFitGenes) Len() int { 30 | return len(s) 31 | } 32 | 33 | // Swap two elements 34 | func (s CurveFitGenes) Swap(i, j int) { 35 | s[i], s[j] = s[j], s[i] 36 | } 37 | 38 | // Return whether one element is less than another 39 | func (s CurveFitGenes) Less(i, j int) bool { 40 | return s[i].Score() < s[j].Score() 41 | } 42 | 43 | /** 44 | * Gene 45 | * Gene 46 | * Gene 47 | */ 48 | 49 | // Return 50 | func (self *CurveFitGene) Score() float64 { 51 | return Delta( 52 | self.F, 53 | func(t float64) float64 { 54 | return 2010*t*t - 200*t - 133. 55 | return 8100*t*t*t - 200*t*t + t - 133. 56 | }, 57 | ) 58 | } 59 | 60 | // Mix two genes 61 | func (s *CurveFitGene) Mix(c *CurveFitGene) CurveFitGene { 62 | gene := CurveFitGene{s.A, s.B, s.C} 63 | 64 | switch rand.Int() % 3 { 65 | case 0: 66 | gene.A = c.A 67 | case 1: 68 | gene.B = c.B 69 | case 2: 70 | gene.C = c.C 71 | default: 72 | } 73 | 74 | return gene 75 | } 76 | 77 | // Mutate a single gene 78 | func (s *CurveFitGene) Mutate() CurveFitGene { 79 | s.A += rand.NormFloat64() * 10 80 | s.B += rand.NormFloat64() * 10 81 | s.C += rand.NormFloat64() * 10 82 | return *s 83 | } 84 | 85 | // Return a random gene 86 | func RandomCurveFitGene() CurveFitGene { 87 | LOW := -1500.0 88 | HIGH := 1500.0 89 | return CurveFitGene{ 90 | rand.Float64()*(HIGH-LOW) + LOW, 91 | rand.Float64()*(HIGH-LOW) + LOW, 92 | rand.Float64()*(HIGH-LOW) + LOW, 93 | } 94 | } 95 | 96 | /** 97 | * Tertiary shit 98 | * Tertiary shit 99 | * Tertiary shit 100 | */ 101 | 102 | // Make Real Functions easier to write 103 | type RealFunc func(t float64) float64 104 | 105 | // Approximation 106 | func Delta(f RealFunc, g RealFunc) float64 { 107 | 108 | SAMPLE_SIZE := 10 109 | LEFT := -50. 110 | RIGHT := 50. 111 | 112 | samples := make([]float64, SAMPLE_SIZE) 113 | 114 | for i := 0; i < SAMPLE_SIZE; i++ { 115 | samples[i] = rand.Float64()*(RIGHT-LEFT) + LEFT 116 | } 117 | 118 | // Omit random sampling for this problem 119 | 120 | samples = []float64{ 121 | -4.0, -3.0, -2.0, 1.0, 122 | 0.0, 123 | 1.0, 2.0, 3.0, 4.0, 124 | } 125 | 126 | sort.Float64s(samples) 127 | 128 | totalError := 0.0 129 | 130 | for _, t := range samples { 131 | totalError += math.Abs(f(t)/1000. - g(t)/1000.) 132 | } 133 | 134 | return totalError 135 | } 136 | 137 | // Return values of a function 138 | func (s *CurveFitGene) F(t float64) float64 { 139 | return s.A*t*t + s.B*t + s.C 140 | } 141 | --------------------------------------------------------------------------------