Commits

dan mackinlay committed b4c2e4a

pseudo-bitwise operator converges well. a little TOO well.

Comments (0)

Files changed (4)

privateer_pyevolve/PrivateerCrossovers.py

 from __future__ import division
 import random
 import math
-
-MANTISSA_BITS = 53 #max python 64 bit mantissa size
-MANTISSA_DENOM = 2<<MANTISSA_BITS
+from bitwise_utils import MANTISSA_BITS, bitcross
 
 def G1DListCrossoverMean(genome, **args):
     """Ultra-stupid crossover taking the mean of both parents. Not very useful -

privateer_pyevolve/PrivateerMutators.py

+from __future__ import division
+import random
+import math
+import sys
+from bitwise_utils import MANTISSA_BITS, bitcross, clip
+from pyevolve import Util
+from pyevolve import Consts
+
+def G1DListMutatorRealPseudoBitwiseAuto(genome, **args):
+    """ The mutator of G1DList, pseudo-bitwise Mutator. only permute sign and mantissa. Careful about using this to converge to zero, since mutation size decreases as the mutation rate does
+    """
+    if args["pmut"] <= 0.0: return 0
+    mutations = int(random.expovariate(1./args["pmut"])*53. + 0.5)
+
+    for it in range(mutations):
+        listSize = len(genome)
+        target_i = random.randint(0, listSize-1)
+        source = genome[target_i]
+        
+        if  Util.randomFlipCoin(1/53.):
+            #sign flip
+            genome[target_i] *= -1
+            continue
+        #else
+        src_exp = math.frexp(source)[1]
+        delta_exp = src_exp-random.randint(0,52)
+        if delta_exp < sys.float_info.min_exp:
+            continue
+        delta = 2.**(delta_exp)
+        delta *= (2.*random.randint(0, 1)-1)
+        print "delta:", delta
+        final_value = source + delta
+        final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax))
+        final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin))
+        genome[target_i] = final_value
+        
+    return mutations
+    
+def G1DListCrossoverBitwise(genome, **args):
+    """bitwise uniform crossover for floats. Warning, potentially breaks range
+    constraints."""
+    sister = None
+    brother = None
+    gMom = args["mom"]
+    gDad = args["dad"]
+
+    sister = gMom.clone()
+    brother = gDad.clone()
+    sister.resetStats()
+    brother.resetStats()
+    
+    for i in xrange(len(gMom)):
+        mask = random.getrandbits(MANTISSA_BITS) 
+        mantissaDad, expDad = math.frexp(gDad[i])
+        mantissaMom, expMom = math.frexp(gMom[i])
+        baseExp = max(expMom, expDad)
+        # import pdb; pdb.set_trace()
+        
+        mantissaDad = int(mantissaDad*2.**(MANTISSA_BITS-baseExp+expDad))
+        mantissaMom = int(mantissaMom*2.**(MANTISSA_BITS-baseExp+expMom))
+        
+        #Not quite sure why i seem to need the -1 in here, but it makes me
+        #distrust the function
+        sister[i] = bitcross(mantissaDad, mantissaMom, mask) *\
+          2.**(baseExp-MANTISSA_BITS)
+        brother[i] = bitcross(mantissaMom, mantissaDad, mask) *\
+          2.**(baseExp-MANTISSA_BITS)
+
+        # sister[i] = clip(sister[i],
+        #   gMom.getParam('rangemin'),
+        #   gMom.getParam('rangemax'))
+        # brother[i] = clip(brother[i],
+        #   gMom.getParam('rangemin'),
+        #   gMom.getParam('rangemax'))
+    
+    return (sister, brother)
+

privateer_pyevolve/bitwise_utils.py

+from __future__ import division
+import random
+import math
+
+TOTAL_BITS = 64
+MANTISSA_BITS = 53 #max python 64 bit mantissa size
+MANTISSA_DENOM = 2<<MANTISSA_BITS
+
+def bitcross(i1, i2, mask):
+    """return a new int, containing its chosen from i1 or i2 depending on whther the mask string is 1 or 0"""
+    return (i1 & mask) | (i2 & ~mask)
+
+def test_mantissa_mathematics():
+    """does all my mantisssa maths work? well, if this is stable it does"""
+    def rndtrip(f): return int((2<<53)*f)/float(2<<53)
+    f=1.0/3.0
+    for i in range(100):
+       print f.hex()
+       f=rndtrip(f)
+
+def clip(f, lbound, ubound):
+    return min(max(f, lbound), ubound)
+
+def float2bitsNexp(f):
+    """
+    we want to flip float bits contextually, i.e. not using the whole range of the float. a bit flip is only allowed to at most double the magnitufe of the thing.
+    doesn't work yet
+    """
+    mantissa, fexp = math.frexp(f)
+    mantissa = int(mantissa * 2.**(MANTISSA_BITS + 1))
+    
+
+def bits2float(mantissa, exp):
+    """doesn't work yet"""
+    pass

privateer_pyevolve/privateer_sim.py

 import matplotlib.pyplot as plt
 import market
 import PrivateerCrossovers
+import PrivateerMutators
 
 import argparse
 
     genome = G1DList.G1DList(1)
 
     # Sets the range max and min of the 1D List
-    # sigma is delicate - without it being set high, convergence is to a non-zero value
-    #TODO - explore the sensitivity of this
-    genome.setParams(rangemin=-20.0, rangemax=20.0,
-      gauss_mu=0.00, gauss_sigma=10.)
+    genome.setParams(rangemin=-20.0, rangemax=20.0)
         
     genome.initializator.set(Initializators.G1DListInitializatorReal)
     
     genome.evaluator.set(value_of_lifetime)
     
     # Mutator function 
-    genome.mutator.set(Mutators.G1DListMutatorRealGaussian)
-    #genome.mutator.set(Mutators.G1DListMutatorRealRange)
+    # genome.mutator.set(Mutators.G1DListMutatorRealGaussian)
+    # genome.mutator.set(Mutators.G1DListMutatorRealRange)
+    genome.mutator.set(PrivateerMutators.G1DListMutatorRealPseudoBitwiseAuto)
     
     # Crossover function must be set to something that can handle 1-elem list
     # genome.crossover.set(Crossovers.G1DListCrossoverUniform)
     
     ga_engine.stepCallback.set(update_plot)
     
-    # ga_engine.setMutationRate(0.05)
+    ga_engine.setMutationRate(0.01)
     # 
     # ga_engine.setElitism(True)
     # ga_engine.setElitismReplacement(80)