Source code for pyec.distribution.basic

from numpy import *
import numpy.linalg as la
import binascii, struct
from pyec.config import Config, ConfigBuilder
from pyec.util.registry import BENCHMARKS
from pyec.util.TernaryString import TernaryString

[docs]class Distribution(object): """A Distribution that can be sampled""" def __init__(self, config): super(Distribution, self).__init__() self.config = config def __call__(self, **kwargs): """Get a single sample from the distribution""" return self.batch(1)[0]
[docs] def batch(self, sampleSize): """Get a sample from the distribution""" pass
[docs]class ProposalDistribution(Distribution): """A proposal distribution for e.g. simulated annealing"""
[docs] def adjust(self, rate): """given the current acceptance rate, alter the distribution as needed""" pass
[docs] def densityRatio(self, x1, x2, i=None): """given two points, give the ratio of the densities p(x1) / p(x2)""" pass
[docs]class PopulationDistribution(Distribution): """A distribution governing a population algorithm"""
[docs] def update(self, n, population): """ Update the distribution with the latest population population is a list of (point, score) tuples If config.sorted is True, the list will be sorted by descending score. """ pass
[docs] def run(self, segment='test', fitness=None, extraArgs=[], **kwargs): from pyec.trainer import Trainer if fitness is None: fitness = BENCHMARKS.load(self.config.function, *extraArgs) self.config.segment = segment if hasattr(fitness, 'center'): self.config.center = fitness.center self.config.scale = fitness.scale if hasattr(fitness, 'numInputs'): self.config.numInputs = fitness.numInputs self.config.numOutputs = fitness.numOutputs self.config.numHidden = fitness.numHidden self.config.netPattern = fitness.netPattern self.config.fitness = fitness try: fitness.algorithm = self fitness.config = self.config except: pass if hasattr(fitness, 'initial'): self.config.initialDistribution = fitness.initial self.initial = self.config.initialDistribution trainer = Trainer(fitness, self, **kwargs) trainer.train() self.trainer = trainer return fitness
[docs] def convert(self, x): """ Convert a point to a scorable representation x - the candidate solution """ return x
@classmethod
[docs] def configure(cls, generations, populationSize, dimension=1, function=None): """ Return a Config object """ return cls.configurator().configure(generations, populationSize, dimension, function)
@classmethod
[docs] def configurator(cls): """ Return a ConfigurationBuilder """ return ConfigBuilder()
[docs]class Gaussian(ProposalDistribution, PopulationDistribution): """ A Gaussian Proposal Distribution """ def __init__(self, config): super(Gaussian, self).__init__(config) self.var = 1. if hasattr(config, 'spaceScale') and config.spaceScale is not None: self.var = config.spaceScale / 2. elif hasattr(config, 'varInit') and config.varInit is not None: self.var = config.varInit self.varIncr = 1.05 self.usePrior = hasattr(config, 'usePrior') and config.usePrior or False def __call__(self, **kwargs): center = zeros(self.config.dim) if self.usePrior and kwargs.has_key('prior'): center = kwargs['prior'] # vary the mixture point var = self.variance() if kwargs.has_key('idx') and hasattr(var, '__len__'): var = var[kwargs['idx']] varied = random.randn(self.config.dim) * var + center # check bounds; call again if outside bounds if self.config.bounded: try: if not self.config.in_bounds(varied): return self.__call__(**kwargs) except RuntimeError, msg: print "Recursion error: ", varied print abs(varied - self.config.center) print self.config.scale return varied def batch(self, popSize): return [self.__call__(idx=i) for i in xrange(popSize)] def density(self, x, center): var = self.variance() if isinstance(var, ndarray): var = var[0] #print x diff = center - x if sqrt((diff * diff).sum()) > 5. * var: return 0.0 covar = var * var * identity(len(x)) diff = center - x pow = -.5 * dot(diff, dot(la.inv(covar), diff)) d = ((((2*pi)**(len(x))) * la.det(covar)) ** -.5) * exp(pow) return d def variance(self): return self.var def adjust(self, rate): if not hasattr(rate, '__len__'): if rate < .23: self.var /= self.varIncr else: if self.var < self.config.scale / 5.: self.var *= self.varIncr return self.var = self.var * ones(len(rate)) for i in xrange(len(rate)): if rate[i] < .23: self.var[i] /= self.varIncr else: if self.var[i] < self.config.scale / 5.: self.var[i] *= self.varIncr #print rate, self.var def densityRatio(self, x1, x2, i = None): if self.usePrior: return 1. else: if i is None: var = self.var else: var = self.var[i] return exp((1./(2*(var**2))) * ((x2 ** 2).sum() - (x1 ** 2).sum()))
[docs]class Bernoulli(Distribution): def __init__(self, config): super(Bernoulli, self).__init__(config) self.dim = config.dim self.bitFlipProb = .5 def __call__(self, **kwargs): return random.binomial(1, self.bitFlipProb, self.dim) def batch(self, popSize): return [self.__call__() for i in xrange(popSize)]
[docs]class BernoulliTernary(Distribution): def __init__(self, config): super(BernoulliTernary, self).__init__(config) self.dim = config.dim def __call__(self, **kwargs): numBytes = int(ceil(self.dim / 8.0)) numFull = self.dim / 8 initial = '' if numBytes != numFull: extra = self.dim % 8 initMask = 0 for i in xrange(extra): initMask <<= 1 initMask |= 1 initial = struct.pack('B',initMask) base = long(binascii.hexlify(random.bytes(numBytes)), 16) known = long(binascii.hexlify(initial + '\xff'*numFull), 16) return TernaryString(base, known) def batch(self, popSize): return [self.__call__() for i in xrange(popSize)]
[docs]class FixedCube(ProposalDistribution): def __init__(self, config): super(FixedCube, self).__init__(config) self.scale = self.config.scale self.center = self.config.center if hasattr(config, 'in_bounds'): if hasattr(config.in_bounds, 'extent'): self.center, self.scale = config.in_bounds.extent() def __call__(self, **kwargs): point = (random.random_sample(self.config.dim) - .5) * 2 * self.scale + self.center while self.config.bounded and not self.config.in_bounds(point): point = (random.random_sample(self.config.dim) - .5) * 2 * self.scale + self.center return point def batch(self, popSize): return [self.__call__() for i in xrange(popSize)] def densityRatio(self, x1, x2): return 1. def adjust(self, rate): pass