|
| 1 | +#! /usr/bin/env python |
| 2 | + |
| 3 | +""" |
| 4 | +experiment in using fractals to fit a set of values |
| 5 | +
|
| 6 | +may or may not work |
| 7 | +""" |
| 8 | + |
| 9 | +import math |
| 10 | + |
| 11 | +from pygene.gene import FloatGene, ComplexGene |
| 12 | +from pygene.gene import IntGene, OrBitGene, rndPair |
| 13 | +from pygene.organism import Organism |
| 14 | +from pygene.population import Population |
| 15 | + |
| 16 | +# data set to model |
| 17 | + |
| 18 | +targetData = [432, 444, 520, 419, 450, 540, 625] |
| 19 | +targetDataLen = len(targetData) |
| 20 | + |
| 21 | +# gene classes for fractals |
| 22 | + |
| 23 | +class OrgGene(ComplexGene): |
| 24 | + """ |
| 25 | + gene to use for initial value |
| 26 | + """ |
| 27 | + mutProb = 0.03 |
| 28 | + mutAmt = 0.5 |
| 29 | + |
| 30 | + randMin = -2.0 |
| 31 | + randMax = 2.0 |
| 32 | + |
| 33 | +class DeltaGene(ComplexGene): |
| 34 | + """ |
| 35 | + gene to use for motion |
| 36 | + """ |
| 37 | + mutProb = 0.03 |
| 38 | + mutAmt = 1.0 |
| 39 | + |
| 40 | + rndMin = -0.4 |
| 41 | + rndMax = 0.4 |
| 42 | + |
| 43 | + |
| 44 | +class IterationsGene(IntGene): |
| 45 | + """ |
| 46 | + gene that controls number of mandelbrot iterations |
| 47 | + """ |
| 48 | + mutProb = 0.001 |
| 49 | + randMin = 2 |
| 50 | + randMax = 10 |
| 51 | + |
| 52 | +# utility func - standard deviation |
| 53 | + |
| 54 | +def sdev(dataset): |
| 55 | + |
| 56 | + n = float(len(dataset)) |
| 57 | + mean = sum(dataset) / n |
| 58 | + devs = [(x - mean) ** 2 for x in dataset] |
| 59 | + sd = math.sqrt(sum(devs) / n) |
| 60 | + return mean, sd |
| 61 | + |
| 62 | +# organism class |
| 63 | + |
| 64 | +class FracOrganism(Organism): |
| 65 | + """ |
| 66 | + organism class |
| 67 | + """ |
| 68 | + genome = { |
| 69 | + 'init':OrgGene, |
| 70 | + 'delta':DeltaGene, |
| 71 | + 'iterations':IterationsGene, |
| 72 | + ) |
| 73 | + |
| 74 | + maxIterations = 100 |
| 75 | + |
| 76 | + def fitness(self): |
| 77 | + """ |
| 78 | + fitness is the standard deviation of the ratio of |
| 79 | + each generated value to each target value |
| 80 | + """ |
| 81 | + guessData = self.getDataSet() |
| 82 | + badness = 0.0 |
| 83 | + ratios = [100000.0 * guessData[i] / targetData[i] \ |
| 84 | + for i in xrange(targetDataLen)] |
| 85 | + try: |
| 86 | + sd, mean = sdev(ratios) |
| 87 | + var = sd / mean |
| 88 | + badness = var, sd, mean |
| 89 | + except: |
| 90 | + #raise |
| 91 | + badness = 10000.0, None, None |
| 92 | + return badness |
| 93 | + |
| 94 | + def getDataSet(self): |
| 95 | + """ |
| 96 | + computes the data set resulting from genes |
| 97 | + """ |
| 98 | + guessData = [] |
| 99 | + org = self['init'] |
| 100 | + delta = self['delta'] |
| 101 | + niterations = self['iterations'] |
| 102 | + for i in xrange(targetDataLen): |
| 103 | + #guessData.append(self.mand(org, niterations)) |
| 104 | + guessData.append(self.mand(org)) |
| 105 | + org += delta |
| 106 | + return guessData |
| 107 | + |
| 108 | + def mand_old(self, org, niterations): |
| 109 | + """ |
| 110 | + performs the mandelbrot calculation on point org for |
| 111 | + niterations generations, |
| 112 | + returns final magnitude |
| 113 | + """ |
| 114 | + c = complex(0,0) |
| 115 | + |
| 116 | + for i in xrange(niterations): |
| 117 | + c = c * c + org |
| 118 | + |
| 119 | + return abs(c) |
| 120 | + |
| 121 | + def mand(self, org): |
| 122 | + """ |
| 123 | + returns the number of iterations needed for abs(org) |
| 124 | + to exceed 1.0 |
| 125 | + """ |
| 126 | + i = 0 |
| 127 | + c = complex(0,0) |
| 128 | + while i < self.maxIterations: |
| 129 | + if abs(c) > 1.0: |
| 130 | + break |
| 131 | + c = c * c + org |
| 132 | + i += 1 |
| 133 | + return i |
| 134 | + |
| 135 | +def newOrganism(self=None): |
| 136 | + |
| 137 | + return FracOrganism( |
| 138 | + init=OrgGene, |
| 139 | + delta=DeltaGene, |
| 140 | + iterations=IterationsGene, |
| 141 | + ) |
| 142 | + |
| 143 | +class FracPopulation(Population): |
| 144 | + |
| 145 | + species = FracOrganism |
| 146 | + initPopulation = 100 |
| 147 | + |
| 148 | + # cull to this many children after each generation |
| 149 | + childCull = 6 |
| 150 | + |
| 151 | + # number of children to create after each generation |
| 152 | + childCount = 30 |
| 153 | + |
| 154 | + # enable addition of random new organisms |
| 155 | + newOrganism = newOrganism |
| 156 | + numNewOrganisms = 5 |
| 157 | + |
| 158 | + # keep best 5 parents |
| 159 | + incest = 5 |
| 160 | + |
| 161 | + |
| 162 | +# create an initial random population |
| 163 | + |
| 164 | +pop = FracPopulation() |
| 165 | + |
| 166 | + |
| 167 | +# now a func to run the population |
| 168 | +def main(): |
| 169 | + try: |
| 170 | + while True: |
| 171 | + # execute a generation |
| 172 | + pop.gen() |
| 173 | + |
| 174 | + # and dump it out |
| 175 | + #print [("%.2f %.2f" % (o['x1'], o['x2'])) for o in pop.organisms] |
| 176 | + best = pop.organisms[0] |
| 177 | + print "fitness=%s" % (best.fitness(),) |
| 178 | + |
| 179 | + except KeyboardInterrupt: |
| 180 | + pass |
| 181 | + |
| 182 | + |
| 183 | +if __name__ == '__main__': |
| 184 | + main() |
| 185 | + |
| 186 | + |
0 commit comments