diff --git a/README.rst b/README.rst index 0eab496..7bdae7b 100644 --- a/README.rst +++ b/README.rst @@ -20,7 +20,7 @@ A **G**\ enetic **A**\ lgorithm **F**\ ramework in py\ **T**\ hon :target: https://www.python.org/downloads/release/python-351/ :alt: platform -.. image:: https://img.shields.io/badge/pypi-v0.6.0-blue.svg +.. image:: https://img.shields.io/badge/pypi-v0.5.5-blue.svg :target: https://pypi.python.org/pypi/gaft/ :alt: versions diff --git a/gaft/__init__.py b/gaft/__init__.py index 78aabb6..a217d3e 100644 --- a/gaft/__init__.py +++ b/gaft/__init__.py @@ -3,7 +3,7 @@ from .engine import GAEngine -__version__ = '0.6.0' +__version__ = '0.5.5' __author__ = 'ShaoZhengjiang ' # Set root logger. diff --git a/gaft/components/binary_individual.py b/gaft/components/binary_individual.py index c9a68a1..b6b2274 100644 --- a/gaft/components/binary_individual.py +++ b/gaft/components/binary_individual.py @@ -14,21 +14,23 @@ class BinaryIndividual(IndividualBase): - def __init__(self, ranges, eps=0.001): - ''' - Class for individual in population. Random solution will be initialized - by default. + ''' + Class for individual in population. Random solution will be initialized + by default. - NOTE: The decrete precisions for different components in varants may be - adjusted automatically (possible precision loss) if eps and ranges - are not appropriate. + :param ranges: value ranges for all entries in solution. + :type ranges: tuple list - :param ranges: value ranges for all entries in solution. - :type ranges: list of range tuples. e.g. [(0, 1), (-1, 1)] + :param eps: decrete precisions for binary encoding, default is 0.001. + :type eps: float or float list (with the same length with ranges) - :param eps: decrete precisions for binary encoding, default is 0.001. - :type eps: float or float list with the same length with ranges. - ''' + .. Note: + + The decrete precisions for different components in varants may be + adjusted automatically (possible precision loss) if eps and ranges + are not appropriate. + ''' + def __init__(self, ranges, eps=0.001): super(self.__class__, self).__init__(ranges, eps) # Lengths for all binary sequence in chromsome and adjusted decrete precisions. @@ -47,8 +49,7 @@ def __init__(self, ranges, eps=0.001): self.init() def encode(self): - ''' - Encode solution to gene sequence in individual using different encoding. + ''' Encode solution to gene sequence in individual using different encoding. ''' chromsome = [] for var, (a, _), length, eps in zip(self.solution, self.ranges, @@ -58,8 +59,7 @@ def encode(self): return chromsome def decode(self): - ''' - Decode gene sequence to solution of target function. + ''' Decode gene sequence to solution of target function. ''' solution = [self.decimalize(self.chromsome[start: end], eps, lower_bound) for (start, end), (lower_bound, _), eps in @@ -76,12 +76,16 @@ def _get_gene_indices(self): @staticmethod def binarize(decimal, eps, length): - ''' - Helper function to convert a float to binary sequence. + ''' Helper function to convert a float to binary sequence. + + :param decimal: the decimal number to be converted + :type decimal: float + + :param eps: the decrete precision of binary sequence + :type eps: float - :param decimal: the decimal number to be converted. - :param eps: the decrete precision of binary sequence. :param length: the length of binary sequence. + :type length: int ''' n = int(decimal/eps) bin_str = '{:0>{}b}'.format(n, length) @@ -89,8 +93,16 @@ def binarize(decimal, eps, length): @staticmethod def decimalize(binary, eps, lower_bound): - ''' - Helper function to convert a binary sequence back to decimal number. + ''' Helper function to convert a binary sequence back to decimal number. + + :param binary: The binary list to be converted + :type binary: list of int + + :param eps: the decrete precision of binary sequence + :type eps: float + + :param lower_bound: the lower bound for decimal number + :type lower_bound: float ''' bin_str = ''.join([str(bit) for bit in binary]) return lower_bound + int(bin_str, 2)*eps diff --git a/gaft/components/decimal_individual.py b/gaft/components/decimal_individual.py index 1d2791e..eb41975 100644 --- a/gaft/components/decimal_individual.py +++ b/gaft/components/decimal_individual.py @@ -8,6 +8,12 @@ class DecimalIndividual(IndividualBase): ''' Individual with decimal encoding. + + :param ranges: value ranges for all entries in solution. + :type ranges: tuple list + + :param eps: decrete precisions for binary encoding, default is 0.001. + :type eps: float or float list (with the same length with ranges) ''' def __init__(self, ranges, eps=0.001): super(self.__class__, self).__init__(ranges, eps) @@ -15,8 +21,12 @@ def __init__(self, ranges, eps=0.001): self.init() def encode(self): + ''' Encode solution to gene sequence + ''' return self.solution def decode(self): + ''' Decode gene sequence to decimal solution + ''' return self.solution diff --git a/gaft/components/individual.py b/gaft/components/individual.py index eaa1ee5..0e59a6a 100644 --- a/gaft/components/individual.py +++ b/gaft/components/individual.py @@ -56,11 +56,17 @@ def __set__(self, obj, precisions): class IndividualBase(object): ''' Base class for individuals. + + :param ranges: value ranges for all entries in solution. + :type ranges: tuple list + + :param eps: decrete precisions for binary encoding, default is 0.001. + :type eps: float or float list (with the same length with ranges) ''' # Solution ranges. ranges = SolutionRanges() - # Original decrete precisions (provided by users). + # Orginal decrete precisions (provided by users). eps = DecretePrecision() # Actual decrete precisions used in GA. @@ -74,17 +80,17 @@ def __init__(self, ranges, eps): self.solution, self.chromsome = [], [] def init(self, chromsome=None, solution=None): - ''' - Initialize the individual by providing chromsome or solution. - - If both chromsome and solution are provided, only the chromsome would - be used. If neither is provided, individual would be initialized randomly. + ''' Initialize the individual by providing chromsome or solution. :param chromsome: chromesome sequence for the individual - :type chromsome: list of float/int. + :type chromsome: list of (float / int) :param solution: the variable vector of the target function. - :type solution: list of float. + :type solution: list of float + + .. Note:: + If both chromsome and solution are provided, only the chromsome would + be used. If neither is provided, individual would be initialized randomly. ''' if not any([chromsome, solution]): self.solution = self._rand_solution() @@ -99,8 +105,7 @@ def init(self, chromsome=None, solution=None): return self def clone(self): - ''' - Clone a new individual from current one. + ''' Clone a new individual from current one. ''' indv = self.__class__(deepcopy(self.ranges), eps=deepcopy(self.eps)) indv.init(chromsome=deepcopy(self.chromsome)) @@ -108,18 +113,22 @@ def clone(self): def encode(self): - ''' *NEED IMPLIMENTATION* + ''' **NEED IMPLIMENTATION** + Convert solution to chromsome sequence. - :return chromsome: The chromsome sequence, float list. + :return: The chromsome sequence + :rtype: list of float ''' raise NotImplementedError def decode(self): - ''' *NEED IMPLIMENTATION* + ''' **NEED IMPLIMENTATION** + Convert chromsome sequence to solution. - :return solution: The solution vector, float list. + :return: The solution vector + :rtype: list of float ''' raise NotImplementedError diff --git a/gaft/components/population.py b/gaft/components/population.py index 29130bd..8977cbe 100644 --- a/gaft/components/population.py +++ b/gaft/components/population.py @@ -5,8 +5,7 @@ class Memoized(object): - ''' - Descriptor for population statistical varibles caching. + ''' Descriptor for population statistical varibles caching. ''' def __init__(self, func): self.func = func @@ -34,8 +33,11 @@ def __call__(self, fitness): class Individuals(object): - ''' - Descriptor for all individuals in population. + ''' Descriptor for all individuals in population. + + .. Note:: + Use this descriptor to ensure the individual related flags can be updated + when the population indivduals are changed. ''' def __init__(self, name): self.name = '_{}'.format(name) @@ -50,21 +52,19 @@ def __set__(self, instance, value): class Population(object): + ''' Class for representing population in genetic algorithm. + + :param indv_template: A template individual to clone all the other + individuals in current population. + :type indv_template: :obj:`gaft.components.IndividualBase` + :param size: The size of population, number of individuals in population. + :type size: int + ''' # All individuals. individuals = Individuals('individuals') def __init__(self, indv_template, size=100): - ''' - Class for representing population in genetic algorithm. - - :param indv_template: A template individual to clone all the other - individuals in current population. - - :param size: The size of population, number of individuals in population. - :type size: int - - ''' # Population size. if size % 2 != 0: raise ValueError('Population size must be an even number') @@ -78,8 +78,7 @@ def __init__(self, indv_template, size=100): # Container for all individuals. class IndvList(list): - ''' - A proxy class inherited from built-in list to contain all + ''' A proxy class inherited from built-in list to contain all individuals which can update the population._updated flag automatically when its content is changed. ''' @@ -118,8 +117,7 @@ def extend(this, iterable_item): self._individuals = IndvList() def init(self, indvs=None): - ''' - Initialize current population with individuals. + ''' Initialize current population with individuals. :param indvs: Initial individuals in population, randomly initialized individuals are created if not provided. @@ -146,21 +144,18 @@ def init(self, indvs=None): return self def update_flag(self): - ''' - Interface for updating individual update flag to True. + ''' Interface for updating individual update flag to True. ''' self._updated = True @property def updated(self): - ''' - Query function for population updating flag. + ''' Query function for population updating flag. ''' return self._updated def new(self): - ''' - Create a new emtpy population. + ''' Create a new emtpy population. ''' return self.__class__(indv_template=self.indv_template, size=self.size) @@ -180,45 +175,71 @@ def __len__(self): return len(self.individuals) def best_indv(self, fitness): - ''' - The individual with the best fitness. + ''' The individual with the best fitness. + :param fitness: Fitness function to calculate fitness value + :type fitness: function + + :return: the best individual in current population + :rtype: :obj:`gaft.components.IndividualBase` ''' all_fits = self.all_fits(fitness) return max(self.individuals, key=lambda indv: all_fits[self.individuals.index(indv)]) def worst_indv(self, fitness): - ''' - The individual with the worst fitness. + ''' The individual with the worst fitness. + + :param fitness: Fitness function to calculate fitness value + :type fitness: function + + :return: the worst individual in current population + :rtype: :obj:`gaft.components.IndividualBase` ''' all_fits = self.all_fits(fitness) return min(self.individuals, key=lambda indv: all_fits[self.individuals.index(indv)]) def max(self, fitness): - ''' - Get the maximum fitness value in population. + ''' Get the maximum fitness value in population. + + :param fitness: Fitness function to calculate fitness value + :type fitness: function + + :return: The maximum fitness value + :rtype: float ''' return max(self.all_fits(fitness)) def min(self, fitness): - ''' - Get the minimum value of fitness in population. + ''' Get the minimum value of fitness in population. + + :param fitness: Fitness function to calculate fitness value + :type fitness: function + + :return: The minimum fitness value + :rtype: float ''' return min(self.all_fits(fitness)) def mean(self, fitness): - ''' - Get the average fitness value in population. + ''' Get the average fitness value in population. + + :param fitness: Fitness function to calculate fitness value + :type fitness: function + + :return: The average fitness value + :rtype: float ''' all_fits = self.all_fits(fitness) return sum(all_fits)/len(all_fits) @Memoized def all_fits(self, fitness): - ''' - Get all fitness values in population. + ''' Get all fitness values in population. + + :param fitness: Fitness function to calculate fitness value + :type fitness: function ''' return [fitness(indv) for indv in self.individuals] diff --git a/setup.py b/setup.py index 963e534..ed5837f 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ :target: https://www.python.org/downloads/release/python-351/ :alt: platform -.. image:: https://img.shields.io/badge/pypi-v0.6.0-blue.svg +.. image:: https://img.shields.io/badge/pypi-v0.5.5-blue.svg :target: https://pypi.python.org/pypi/gaft/ :alt: versions