Full Code of csxeba/evolute for AI

master ea868e5d04e6 cached
30 files
40.6 KB
10.7k tokens
124 symbols
1 requests
Download .txt
Repository: csxeba/evolute
Branch: master
Commit: ea868e5d04e6
Files: 30
Total size: 40.6 KB

Directory structure:
gitextract_mywosglh/

├── .gitignore
├── LICENSE
├── Readme.md
├── evolute/
│   ├── __init__.py
│   ├── evaluation/
│   │   ├── __init__.py
│   │   ├── fitness.py
│   │   └── grade.py
│   ├── initialization/
│   │   ├── __init__.py
│   │   └── initializer.py
│   ├── operators/
│   │   ├── __init__.py
│   │   ├── mate.py
│   │   ├── mutate.py
│   │   ├── operators.py
│   │   └── selection.py
│   ├── population/
│   │   ├── __init__.py
│   │   ├── genetic.py
│   │   └── population.py
│   └── utility/
│       ├── __init__.py
│       ├── describe.py
│       ├── history.py
│       ├── keras_utility.py
│       └── test_utils.py
├── examples/
│   ├── xp_evolve_net.py
│   ├── xp_keras.py
│   ├── xp_quadratic.py
│   └── xp_simple.py
├── requirements.txt
├── setup.py
└── tests/
    ├── test_evaluation.py
    └── test_operator.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Created by .ignore support plugin (hsz.mobi)
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# PyCharm
.idea/

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 Csaba Gor

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Readme.md
================================================
[![codebeat badge](https://codebeat.co/badges/f72db301-fd66-4c05-b1ca-9b8c8196f06e)](https://codebeat.co/projects/github-com-csxeba-evolute-master)
# Evolute
Evolutionary algorithm toolbox

## Documentation

**Evolute** is a simple tool for quick experimentation with evolutionary
algorithms for numerical optimization.

It defines a **population** of individuals, represented as floating point
vectors, and applies a configurable set of evolutionary **operators** to
them in a predefined order.

The order is the following:
1. **Selection**: a subset of individuals are discarded, depending on
their fitness value
2. **Reproduction**: the discarded individuals are replaced by new
individuals, somehow generated from the survivors
3. **Mutation**: mutate some of the individuals
4. **Update**: update the fitnesses of the individuals 

Some nomenclature:
- **individual**: a single member of the population.
- **genotype**: refers to an individual in the encoded state.
*Evolute* encodes information in floating point vectors.
- **locus**: a member of a genotype (a single scalar in the vector)
- **phenotype**: refers to an individual in the decoded state. In the
case of neuroevolution, this would be a neural network object, which
is encoded as a genotype. Evolute is not doing any *genotype - phenotype*
conversion, this has to be implemented by the user in the fitness
calculation.


### Module: *population*

Defines containers for individuals and aggregates the operators
applied to them. Currently the following population types are defined:
- **GeneticPopulation**: can be used for genetic algorithms, simply
evaluates the fitnesses and applies the operators in the above specified
order. Its constructor accepts the following arguments:
  - **loci**: number of elements in an individual's chromosome
  - **fitness_wrapper**: instance of a class in evolute.evaluation
  - **limit**: maximum number of individuals, defaults to 100
  - **operators**: an instance of *evolute.operators.Operators*, see operators later
  - **initializer**: instance of a class defined in evolute.initialization, optional

Will add support for MemeticPopulation, which allows for explicit modification
of the individuals during fitness calculation

An evolutionary optimization can be run using the population.run() method, which
accepts the following arguments:
- **epochs**: how many iterations should be done
- **survival_rate**: reset survival rate
- **mutation_rate**: reset mutation rate
- **force_update_at_every**: at every *k*th iteration, force a complete
fitness-recalculation
- **verbosity**: 0 is silent, > 0 is verbose.
- **history**: evolute.utils.history.History object, in which runtime metrics
can be recorded. If omitted, one is instantiated implicitly.

The run() method returns a history object with generation, best_grade, mean_grade
and grade_stdev recorded by default. 

A population can be saved and loaded with the save() and load() methods, which
produces a gzip-compressed pickle of the Population object.

Single epoch can be also run with the epoch() method and an update can be forced
with the update() method.

For convenience, these methods are defined:
- **epoch()**: use this to evaluate a single epoch
- **update()**: forces a fitness update
- **simple_fitness()**: class factory method, which takes a nude fitness function
and wraps it implicitly with SimpleFitness (see below).
- **get_individual(index)**
- **set_indivudual(index, individual)**
- **get_best()**: the current best individual with the lowest fitness/grade
- **get_champion**: the all-time best individual is alway stored implicitly,
and can be accessed here.
 

### Module: *evaluation*

Defines different wrappers for fitness functions.
**Fitness** is a scalar value assigned to every individual.
Currently in Evolute, the lower fitness is the better.

Since a fitness function can be any kind of logic, fitness wrappers
expect a function pointer or some kind of callable. Some advanced
wrappers are there to support possibly multiple fitness functions
or functions with multiple return values. In the end, the fitness
has to be reduced to a single scalar.

The process of combining multiple fitnesses to a single scalar is
termed **grading** in Evolute.

#### Fitness wrappers

Currently the following fitness wappers are defined in
*evolute.evaluation*:

- **SimpleFitness**: wraps a simple function with a single scalar
return value. Its constructor expects the following arguments:
  - **fitness_function**: a function reference or callable object
  - **constants**: optional dictionary of constants to be passed by name

Variables may be passed to the fitness function during the running of
the algorithm.

- **MultipleFitnesses**: wraps multiple fitness functions. The
constructor expects the following arguments:
  - **functions_by_name**: dictionary of fitness function references
or callable objects. They need to be identified by a unique name or ID
  - **contants_by_function_name**: optional dictionary of arguments (as dicts as well).
They have to be referenced by the same name or ID.
  - **order_by_name**: optional, an ordered iterable of the IDs if call order
matters.
  - **grader**: grader object or any callable which takes the array of
fitnesses and produces a single scalar grade from them. Defaults to
simple summation.

- **MultiReturnFitness**: wrapper for a single fitness function which
returns multiple fitness values. The constructor expects the following
arguments:
  - **number_of_return_values**
  - **constants**: optional
  - **grader**: optional, defaults to simple summation
  
#### Graders

More advanced fitness wrappers expect a Grader instance defined in
*evolute.evaluation.grade* or any callable which accepts a NumPy
array and returns a single scalar.

Some graders are available in *evolute.evaluation*:

- **SumGrader**: simply sums the fitness values
- **WeightedSumGrader**: accepts a set of weights in its constructor
and produces a weighted sum (dot product) with the fitness values.

### Module: *initialization*

This module defines initializers: objects for random population
initialization strategies. Currently the following distributions
are available in *evolute.initialization*:

- **NormalRandom**: with customizable **mean** and **stdev**
- **UniformRandom**: with customizable **low** and **high**
- **OrthogonalNormal**: produces a diagonal random matrix 
 
### Module: *operators*
 
Evolutionary operators are defined here. This module defines an
**Operators** class, which aggregates all the operators needed to
run an evolutionary optimization. Operators' constructor takes the
following arguments:
- **selection_op**
- **mutate_op**
- **mate_op**

Submodules define the particular operator types, which are the following:

#### Selection

During selection, a subset of individuals are discarded. The logic by
which these are specified depends on the actual implementation:

- **Elitism**: selects the top m% of individuals. Its constructor
accepts the following arguments:
  - **selection_rate**: scalar between 0 and 1 to specify the rate of
discarded individuals
  - **mate_op**: a mate operator, which is used to fill up the slots
where individuals are missing (applies reproduction). Details on these
later.
  - **exclude_self_mating**: bool, whether to disallow mating an individual
with itself

If no selection operator is defined, every selection-using class defaults
to *Elitism*.

#### Mate

Mating is defined as some kind of combination of two individuals to
reproduce a new individual. Currently the following mate operators
are defined:

- **LambdaMate**: wraps a user-defined function, which takes two
individuals and produces a single individual
- **RandomPickMate**: randomly pics loci from the two genotypes
- **SmoothMate**: takes the mean of the two genotypes
- **ScatterMateWrapper**: wrapper for any mate operator. When applied,
it adds gaussian noise to the new individual. Its constructor expects
the following parameters:
  - **base**: reference to the base mate operator object
  - **stdev**: standard deviation of the additive gaussian noise
  
If no mate operator is defined, every mate-using class defaults to
*RandomPickMate*.

#### Mutate

This operator takes the whole population and mutates its individuals
by perturbing them with some kind of noise. The following mutation
operators are available:

- **UniformLocuswiseMutation**: adds uniform distributed noise to
individuals. Mutants are determined on the locus level, and mutation
rate (see below) is adjusted for this. Its constructor takes the
following arguments:
  - **rate**: rate by which mutations occur in the population. It has
  to be given as a rate of individuals but it is implicitly corrected
  for loci.
  - **low** and **high**: parameters of the uniform distribution
- **NormalIndividualwiseMutation**: adds normal random noise to
individuals. Mutants are determined on the individuals' level. Its
constructor takes the following arguments:
  - **rate**
  - **stdev**
 
If no mutate operator is defined, every mutate-using class defaults
to *UniformLocuswiseMutation*.

### Module: utility

Some useful stuff here. Maybe the most interesting is the
*evolute.keras_utility* module, which defines some helpers to interface
with Keras and do some Neuroevolution on the weights of a network.


================================================
FILE: evolute/__init__.py
================================================
from .population import GeneticPopulation


================================================
FILE: evolute/evaluation/__init__.py
================================================
from .fitness import FitnessBase, SimpleFitness, MultipleFitnesses, MultiReturnFitness
from .grade import GraderBase, SumGrader, WeightedSumGrader


================================================
FILE: evolute/evaluation/fitness.py
================================================
import numpy as np

from .grade import SumGrader


class FitnessBase:

    def __init__(self, no_fitnesses):
        self.no_fitnesses = no_fitnesses

    def __call__(self, phenotype):
        raise NotImplementedError


class SimpleFitness(FitnessBase):

    def __init__(self, fitness_function, constants: dict=None, **kw):
        super().__init__(no_fitnesses=1)
        self.function = fitness_function
        self.constants = {} if constants is None else constants
        self.constants.update(kw)

    def __call__(self, phenotype, **variables):
        return self.function(phenotype, **self.constants, **variables)


class MultipleFitnesses(FitnessBase):

    def __init__(self, functions_by_name, constants_by_function_name=None, order_by_name=None, grader=None):
        super().__init__(no_fitnesses=len(functions_by_name))
        if len(functions_by_name) < 2:
            raise ValueError("MultipleFitnesses needs more than one fitness!")
        self.functions = functions_by_name
        self.order = order_by_name or list(self.functions)
        self.constants = constants_by_function_name or {k: {} for k in self.order}
        self.grader = grader or SumGrader()
        if len(self.order) != len(self.functions) or any(o not in self.functions for o in self.order):
            raise ValueError("The specified order is wrong: {}".format(self.order))
        if len(self.constants) != len(self.functions) or any(k not in self.functions for k in self.constants):
            raise ValueError("The specified constants are wrong: {}".format(self.constants))

    def __call__(self, phenotype, **variables_by_function):
        fitness = np.array(
            [self.functions[funcname](phenotype, **self.constants[funcname], **variables_by_function[funcname])
             for funcname in self.order])
        return self.grader(fitness)


class MultiReturnFitness(FitnessBase):

    def __init__(self, fitness_function, number_of_return_values, constants: dict=None, grader=None):
        super().__init__(no_fitnesses=number_of_return_values)
        self.function = fitness_function
        self.constants = {} if constants is None else constants
        self.grader = SumGrader() if grader is None else grader

    def __call__(self, phenotype, **variables):
        fitness = np.array(self.function(phenotype, **self.constants, **variables))
        return self.grader(fitness)


================================================
FILE: evolute/evaluation/grade.py
================================================
import numpy as np


class GraderBase:

    def __call__(self, fitness):
        raise NotImplementedError


class SumGrader(GraderBase):

    def __call__(self, fitness):
        return np.sum(fitness)


class WeightedSumGrader(GraderBase):

    def __init__(self, weights):
        self.weights = np.ones(1) if weights is None else weights

    def __call__(self, fitness):
        return np.dot(fitness, self.weights)


================================================
FILE: evolute/initialization/__init__.py
================================================
from .initializer import NormalRandom, UniformRandom, OrthogonalNormal

DefaultInitializer = NormalRandom


================================================
FILE: evolute/initialization/initializer.py
================================================
import numpy as np


class Initializer:

    def initialize(self, *shape):
        raise NotImplementedError


class NormalRandom(Initializer):

    def __init__(self, mean=0., stdev=1.):
        self.mean = mean
        self.stdev = stdev

    def initialize(self, *shape):
        return np.random.randn(*shape) * self.stdev + self.mean


class UniformRandom(Initializer):

    def __init__(self, low=-1, high=1.):
        self.low = low
        self.high = high

    def initialize(self, *shape):
        return np.random.uniform(self.low, self.high, shape)


class OrthogonalNormal(Initializer):

    def initialize(self, *shape):
        individials = NormalRandom().initialize(shape)
        d, V = np.linalg.eig(np.cov(individials.T))
        D = np.diag(1. / np.sqrt(d + 1e-7))
        W = V @ D @ V.T
        return individials @ W


================================================
FILE: evolute/operators/__init__.py
================================================
from .mate import DefaultMate, LambdaMate, SmoothMate, RandomPickMate, ScatterMateWrapper
from .mutate import DefaultMutate, UniformLocuswiseMutation, NormalIndividualwiseMutation
from .selection import DefaultSelection, Elitism
from .operators import Operators


================================================
FILE: evolute/operators/mate.py
================================================
import numpy as np


class MateBase:

    def apply(self, ind1, ind2):
        pass

    def __call__(self, ind1, ind2):
        return self.apply(ind1, ind2)


class LambdaMate(MateBase):

    def __init__(self, function_ref, **kw):
        self.kwargs = kw
        self.apply = lambda ind1, ind2: function_ref(ind1, ind2, **self.kwargs)


class RandomPickMate(MateBase):

    def apply(self, ind1, ind2):
        return np.where(np.random.uniform(size=ind1.shape) < 0.5, ind1, ind2)


class SmoothMate(MateBase):

    def apply(self, ind1, ind2):
        return np.mean((ind1, ind2), axis=0)


DefaultMate = RandomPickMate


class ScatterMateWrapper(MateBase):

    def __init__(self, base=DefaultMate, stdev=1.):
        if isinstance(base, type):
            base = base()
        self.base = base
        self.stdev = stdev

    def apply(self, ind1, ind2):
        return self.base(ind1, ind2) + np.random.randn(*ind1.shape) * self.stdev


================================================
FILE: evolute/operators/mutate.py
================================================
import numpy as np


class MutationBase:

    def __init__(self, rate=0.1):
        self.rate = rate
        self.mask = None

    def set_rate(self, rate):
        if rate < 0. or rate > 1.:
            raise ValueError("Mutation rate has to be >= 0 and <= 1")
        self.rate = rate

    def apply(self, individuals, inplace=False):
        raise NotImplementedError

    def __call__(self, individuals, inplace=False):
        return self.apply(individuals)


class UniformLocuswiseMutation(MutationBase):

    def __init__(self, rate=0.1, low=-1., high=1.):
        super().__init__(rate)
        self.low = low
        self.high = high

    def set_params(self, low=None, high=None):
        self.low = self.low if low is None else low
        self.high = self.high if high is None else high

    def apply(self, individuals, inplace=False):
        indshape = individuals.shape
        if self.rate == 0.:
            self.mask = np.zeros(len(individuals), dtype=bool)
            return individuals
        elif self.rate == 1.:
            mask = np.ones(indshape, dtype=bool)
        else:
            mask = np.random.uniform(size=indshape) < (self.rate / indshape[-1])
        self.mask = np.any(mask, axis=1)
        noise = np.random.uniform(self.low, self.high, size=mask.sum())
        if not inplace:
            mutants = individuals.copy()
            mutants[mask] += noise
            return mutants
        individuals[mask] += noise


class NormalIndividualwiseMutation(MutationBase):

    def __init__(self, rate=0.1, stdev=1.):
        super().__init__(rate)
        self.std = stdev

    def set_param(self, stdev):
        self.std = stdev

    def apply(self, individuals, inplace=False):
        mask = np.random.uniform(size=len(individuals)) < self.rate
        noise = np.random.normal(loc=0., scale=self.std, size=(mask.sum(), individuals.shape[-1]))
        if not inplace:
            mutants = individuals.copy()
            mutants[mask] += noise
            return mutants
        individuals[mask] += noise
        self.mask = mask


DefaultMutate = UniformLocuswiseMutation


================================================
FILE: evolute/operators/operators.py
================================================
import numpy as np
from . import DefaultSelection, DefaultMutate, DefaultMate


class Operators:

    def __init__(self, selection_op=None, mutate_op=None, mate_op=None):
        self.selection = DefaultSelection() if selection_op is None else selection_op
        self.mutation = DefaultMutate() if mutate_op is None else mutate_op
        self._clarify_mate_operator(mate_op)

    def _clarify_mate_operator(self, mate_op):
        mate_set_in_selection = self.selection.mate_op is not None
        mate_set_here = mate_op is not None
        if mate_set_in_selection and mate_set_here:
            print(" [w] Evolute: differring mate ops, using the one in Selection!")
        elif mate_set_in_selection and not mate_set_here:
            pass
        elif not mate_set_in_selection and mate_set_here:
            self.selection.set_mate_operator(mate_op)
        elif not mate_set_in_selection and not mate_set_here:
            self.selection.set_mate_operator(DefaultMate())
        else:
            assert False, "O.o"  # w00t

    def invalid_individual_indices(self):
        return np.where(self.selection.mask | self.mutation.mask)[0]


================================================
FILE: evolute/operators/selection.py
================================================
import numpy as np


class SelectionBase:

    def __init__(self, selection_rate=0.5, mate_op=None, exclude_self_mating=True):
        self.mate_op = mate_op
        self.rate = None
        self._selection_mask = None
        self.exclude_self_mating = exclude_self_mating
        self.set_selection_rate(selection_rate)

    @property
    def mask(self):
        return self._selection_mask

    def set_mate_operator(self, mate_op):
        self.mate_op = mate_op

    def _stream_of_parent_indices(self):
        assert self._selection_mask is not None
        survivor_mask = ~self._selection_mask
        arg1 = np.argwhere(survivor_mask)[:, 0]
        assert len(arg1) > 1
        arg2 = np.copy(arg1)
        limit = sum(self._selection_mask)
        n = 0
        while n < limit:
            np.random.shuffle(arg1)
            np.random.shuffle(arg2)
            for ix1, ix2 in zip(arg1, arg2):
                if n >= limit:
                    raise StopIteration
                if self.exclude_self_mating and ix1 == ix2:
                    continue
                yield ix1, ix2
                n += 1

    def set_survival_rate(self, survival_rate):
        if survival_rate <= 0. or survival_rate > 1.:
            raise ValueError("The rate of survival has to be greater than 0 and less or equal to 1")
        self.rate = survival_rate

    def set_selection_rate(self, selection_rate):
        if selection_rate <= 0. or selection_rate > 1.:
            raise ValueError("The rate of selection has to be greater than 0 and less or equal to 1")
        self.rate = 1. - selection_rate

    def apply(self, individuals, fitnesses, inplace=False):
        raise NotImplementedError

    def __call__(self, individuals, fitnesses, inplace=False):
        return self.apply(individuals, fitnesses, inplace)


class Elitism(SelectionBase):

    def apply(self, individuals, fitnesses, inplace=False):
        self._selection_step(individuals, fitnesses)
        if not inplace:
            return self._reproduction_copy(individuals)
        self._reproduction_inplace(individuals)

    def _selection_step(self, individuals, grades):
        limit, loci = individuals.shape
        self._selection_mask = np.ones(limit, dtype=bool)
        if self.rate:
            no_survivors = max(2, int(limit * self.rate))
            survivors = np.argsort(grades)[:no_survivors]
            self._selection_mask[survivors] = False

    def _reproduction_inplace(self, individuals):
        individuals[self._selection_mask] = [
            self.mate_op(individuals[idx1], individuals[idx2])
            for idx1, idx2 in self._stream_of_parent_indices()
        ]

    def _reproduction_copy(self, individuals):
        offspring = individuals.copy()
        new_indivs = [
            self.mate_op(offspring[idx1], offspring[idx2])
            for idx1, idx2 in self._stream_of_parent_indices()
        ]
        offspring[self._selection_mask] = new_indivs
        return offspring


DefaultSelection = Elitism


================================================
FILE: evolute/population/__init__.py
================================================
from .population import Population
from .genetic import GeneticPopulation


================================================
FILE: evolute/population/genetic.py
================================================
from .population import Population


class GeneticPopulation(Population):

    def update_individual(self, index, **fitness_kw):
        self.fitnesses[index] = self.fitness(self.get_individual(index), **fitness_kw)


================================================
FILE: evolute/population/population.py
================================================
import numpy as np

from ..initialization import DefaultInitializer
from ..operators import Operators
from ..evaluation import SimpleFitness
from ..utility.history import History


class Population:

    def __init__(self, loci: int,
                 fitness_wrapper,
                 limit=100,
                 operators=None,
                 initializer=None):
        """
        :param loci: number of elements in an individual's chromosome
        :param fitness_wrapper: accepts an individual, returns fitnesses
        :param limit: maximum number of individuals
        :param operators: an instance of Operators
        :param initializer: instance of a class defined in evolute.initialization
         and index of mutants
        """
        self.loci = loci
        self.limit = limit
        self.fitness = fitness_wrapper
        self.fitnesses = None
        self.operators = Operators() if operators is None else operators

        self.initializer = DefaultInitializer() if initializer is None else initializer
        self.individuals = self.initializer.initialize(self.limit, self.loci)

        self.age = 0
        self.champion = 0

    @classmethod
    def simple_fitness(cls, fitness_callback,
                       loci, limit=100,
                       initializer=None,
                       operators=None,
                       fitness_constants=None):
        fitness_wrapper = SimpleFitness(fitness_callback, {} if fitness_constants is None else fitness_constants)
        return cls(loci=loci, fitness_wrapper=fitness_wrapper, limit=limit,
                   initializer=initializer, operators=operators)

    def get_individual(self, index):
        return self.individuals[index]

    def set_individual(self, index, individual):
        self.individuals[index] = individual

    def get_best(self):
        return self.get_individual(np.argmin(self.fitnesses))

    def get_champion(self):
        return self.get_individual(self.champion)

    def get_fitness_weighted_average_individual(self):
        weights = (self.fitnesses - self.fitnesses.mean()) / self.fitnesses.std()
        return weights @ self.individuals

    def run(self, epochs: int,
            survival_rate: float=0.5,
            mutation_rate: float=0.1,
            force_update_at_every: int=0,
            verbosity: int=1,
            history=None):
        """
        :param epochs: number of epochs to run for
        :param survival_rate: 0-1, how many individuals survive the selection
        :param mutation_rate: 0-1, rate of mutation at each epoch
        :param force_update_at_every: complete reupdate at specified intervals
        :param verbosity: 1 is verbose, > 1 also prints out v - 1 individuals
        :param history: History object in which run stats should be recorded
        :return: history object containing run statistics
        """

        history = (History(["generation", "best_grade", "mean_grade", "grade_std"])
                   if history is None else history)
        self.operators.selection.set_survival_rate(survival_rate)
        self.operators.mutation.set_rate(mutation_rate)
        for epoch in range(1, epochs+1):
            if verbosity:
                print("-" * 50)
                print("Epoch {}/{}".format(epochs, epoch))
            self.epoch(force_update=force_update_at_every and epoch % force_update_at_every == 0,
                       verbosity=verbosity)
            history.record({"generation": self.age,
                            "best_grade": self.fitnesses.min(),
                            "mean_grade": self.fitnesses.mean(),
                            "grade_std": self.fitnesses.std()})
        if verbosity:
            print()
        return history

    def epoch(self, force_update=False, verbosity=1, **fitness_kw):
        if not self.age:
            self._initialize(verbosity, **fitness_kw)

        self.operators.selection(self.individuals, self.fitnesses, inplace=True)
        self.individuals = self.operators.mutation(self.individuals, inplace=False)
        self.update(force_update, verbose=verbosity, **fitness_kw)
        self.age += 1

    def _initialize(self, verbosity, **fitness_kw):
        if verbosity:
            print("EVOLUTION: initial update...")
        self.fitnesses = np.empty(self.limit)
        self.update(forced=True, verbose=verbosity, **fitness_kw)
        if verbosity:
            print("EVOLUTION: initial mean grade :", self.fitnesses.mean())
            print("EVOLUTION: initial std of mean:", self.fitnesses.std())
            print("EVOLUTION: initial best grade :", self.fitnesses.min())

    def update(self, forced=False, verbose=0, **fitness_kw):
        inds = self._invalidated_individual_indices(force_update=forced)
        for ind in inds.flat:
            if verbose:
                print("\rUpdating {}/{}".format(self.limit, ind+1), end="")
            self.update_individual(ind, **fitness_kw)
        if verbose:
            print("\rUpdating {}/{}".format(self.limit, self.limit), end="")
            print(" Best grade:", self.fitnesses.min())
        chump = self.fitnesses.argmin()
        if self.fitnesses[chump] < self.fitnesses[self.champion]:
            self.champion = chump

    def update_individual(self, index, **fitness_kw):
        raise NotImplementedError

    def _invalidated_individual_indices(self, force_update):
        return np.arange(self.limit) if force_update else self.operators.invalid_individual_indices()

    def save(self, path):
        import pickle
        import gzip
        with gzip.open(path, "wb") as handle:
            pickle.dump(self, handle)

    @staticmethod
    def load(path):
        import pickle
        import gzip
        return pickle.load(gzip.open(path, "rb"))


================================================
FILE: evolute/utility/__init__.py
================================================


================================================
FILE: evolute/utility/describe.py
================================================
import numpy as np


def describe(population, show=0):
    showme = np.argsort(population.grades)[:show]
    chain = "-" * 50 + "\n"
    shln = len(str(show))
    for i, index in enumerate(showme, start=1):
        genomechain = ", ".join(
            "{:>6.4f}".format(loc) for loc in
            np.round(population.individuals[index], 4))
        fitnesschain = "[" + ", ".join(
            "{:^8.4f}".format(fns) for fns in
            population.fitnesses[index]) + "]"
        chain += "TOP {:>{w}}: [{:^14}] F = {:<} G = {:.4f}\n".format(
            i, genomechain, fitnesschain, population.grades[index],
            w=shln)
    best_arg = population.grades.argmin()
    chain += "Best Grade : {:7>.4f} ".format(population.grades[best_arg])
    chain += "Fitnesses: ["
    chain += ", ".join("{}".format(f) for f in population.fitnesses[best_arg])
    chain += "]\n"
    chain += "Mean Grade : {:7>.4f}, STD: {:7>.4f}\n" \
        .format(population.grades.mean(), population.grades.std())
    print(chain)


================================================
FILE: evolute/utility/history.py
================================================
class History:

    def __init__(self, aspects=()):
        self.history = {aspect: [] for aspect in ["generation"] + list(aspects)}

    def record(self, data):
        for key in data:
            self.history[key].append(data[key])

    def __getitem__(self, item):
        return self.history[item]


================================================
FILE: evolute/utility/keras_utility.py
================================================
import numpy as np


def get_keras_weights(model, folded=False):
    w_tensors = model.trainable_weights
    if folded:
        return w_tensors
    return np.concatenate([w.flat for w in w_tensors])


def get_keras_number_of_trainables(model):
    return sum(w.size for w in model.trainable_weights)


class WeightFolding:

    def __init__(self, model):
        self.shapes = [w.shape for w in model.get_weights()]
        self.sizes = [np.prod(shape) for shape in self.shapes]

    def __call__(self, individual):
        phenotype = []
        start = 0
        for shape, size in zip(self.shapes, self.sizes):
            end = start + size
            phenotype.append(individual[start:end].reshape(shape))
            start = end
        return phenotype


================================================
FILE: evolute/utility/test_utils.py
================================================
import numpy as np


def is_standardish(array, globally=False, epsilon=1e-7):
    if globally:
        return np.allclose(array.mean(), 0., atol=epsilon) and np.allclose(array.std(), 1., atol=epsilon )
    return np.allclose(array.mean(axis=0), 0., atol=epsilon) and np.allclose(array.std(axis=0), 1., atol=epsilon)


def is_normalish(array, epsilon=1e-7):
    return np.allclose(np.linalg.norm(array, axis=1), 1., atol=epsilon)


================================================
FILE: examples/xp_evolve_net.py
================================================
import numpy as np

from matplotlib import pyplot as plt

from brainforge import LayerStack
from brainforge.layers import DenseLayer
from brainforge.cost import costs

from evolute.operators import ScatterMateWrapper, SmoothMate, Operators
from evolute import GeneticPopulation

np.random.seed(1234)

rX = np.linspace(-6., 6., 200)[:, None]
rY = np.sin(rX)

arg = np.arange(len(rX))
np.random.shuffle(arg)
targ, varg = arg[:100], arg[100:]
targ.sort()
varg.sort()

tX, tY = rX[targ], rY[targ]
vX, vY = rX[varg], rY[varg]

tX += np.random.randn(*tX.shape) / np.sqrt(tX.size*0.25)

loss_fn = costs["mse"]


def fitness(phenotype, layerstack, X, Y):
    layerstack.set_weights(phenotype)
    return loss_fn(layerstack.predict(X), Y)


def forge_layerstack():
    return LayerStack(input_shape=(1,), layers=[
        DenseLayer(30, activation="tanh"),
        DenseLayer(30, activation="tanh"),
        DenseLayer(1, activation="linear")
    ])


def get_population():
    layers = forge_layerstack()
    operators = Operators(mate_op=ScatterMateWrapper(SmoothMate, 3.))
    pop = GeneticPopulation.simple_fitness(limit=100, loci=layers.nparams,
                                           operators=operators,
                                           fitness_callback=fitness,
                                           fitness_constants={"layerstack": layers})
    return layers, pop


def xperiment():
    layers, pop = get_population()
    layers = forge_layerstack()
    tpred = layers.predict(tX)
    vpred = layers.predict(vX)
    plt.ion()
    plt.plot(tX, tY, "b--", alpha=0.5, label="Training data (noisy)")
    plt.plot(rX, rY, "r--", alpha=0.5, label="Validation data (clean)")
    plt.ylim(min(rY)-1, max(rY)+1)
    plt.plot(rX, np.zeros_like(rX), c="grey", linestyle="--")
    tobj, = plt.plot(tX, tpred, "bo", markersize=3, alpha=0.5, label="Training pred")
    vobj, = plt.plot(vX, vpred, "ro", markersize=3, alpha=0.5, label="Validation pred")
    templ = "Batch: {:>5} Cost = {:.4f}"
    t = plt.title(templ.format(0, 0))
    plt.legend()
    batchno = 1
    while 1:
        pop.epoch(X=tX, Y=tY)
        layers.set_weights(pop.get_champion())
        tpred = layers.predict(tX)
        vpred = layers.predict(vX)
        tobj.set_data(tX, tpred)
        vobj.set_data(vX, vpred)
        plt.pause(0.01)
        t.set_text(templ.format(batchno, pop.fitnesses.min()))
        batchno += 1


if __name__ == '__main__':
    xperiment()


================================================
FILE: examples/xp_keras.py
================================================
import numpy as np

from keras.layers import Dense
from keras.models import Sequential
from keras.datasets import mnist
from keras.utils import to_categorical

from evolute import GeneticPopulation
from evolute.evaluation import SimpleFitness
from evolute.initialization import NormalRandom
from evolute.operators import RandomPickMate, Operators, UniformLocuswiseMutation, ScatterMateWrapper
from evolute.utility.keras_utility import WeightFolding


def pull_mnist():
    learning, testing = mnist.load_data()
    Xs, Ys = (learning[0], testing[0]), (learning[1], testing[1])
    Xs = map(lambda x: (x.reshape(-1, 784) - 127.5) / 255., Xs)
    Ys = map(lambda y: to_categorical(y, num_classes=10), Ys)
    return tuple(Xs), tuple(Ys)


def fitness_callback(phenotype, model: Sequential, w_folder, X, Y):
    model.set_weights(w_folder(phenotype))
    cost, acc = model.evaluate(X, Y, verbose=0)
    return cost


(lX, tX), (lY, tY) = pull_mnist()


ann = Sequential([
    Dense(64, activation="tanh", input_dim=lX.shape[1]),
    Dense(lY.shape[1], activation="softmax")
])
ann.compile(optimizer="sgd", loss="categorical_crossentropy", metrics=["acc"])

w_shapes = [w.shape for w in ann.get_weights()]
w_flat = np.concatenate([w.flat for w in ann.get_weights()])
w_folder = WeightFolding(ann)

fitness = SimpleFitness(fitness_function=fitness_callback,
                        constants={"model": ann, "w_folder": w_folder})

population = GeneticPopulation(
    limit=100,
    loci=w_flat.size,
    fitness_wrapper=fitness,
    initializer=NormalRandom(mean=w_flat),
    operators=Operators(mate_op=ScatterMateWrapper(RandomPickMate(), stdev=2.),
                        mutate_op=UniformLocuswiseMutation(low=-3., high=3.))
)

BATCH_SIZE = 128
batch_stream = ((lX[start:start+BATCH_SIZE], lY[start:start+BATCH_SIZE])
                for start in range(0, len(lX), BATCH_SIZE))

population.operators.selection.set_selection_rate(0.98)
population.operators.mutation.set_rate(0.0)
for i, (x, y) in enumerate(batch_stream, start=1):
    population.epoch(X=x, Y=y, verbosity=0)
    ann.set_weights(w_folder(population.get_best()))
    cost, acc = ann.evaluate(tX, tY, verbose=0)
    print("\rBatch: {} Acc: {:.2%}, Cost: {:.4f}".format(i, acc, cost))


================================================
FILE: examples/xp_quadratic.py
================================================
import numpy as np
from matplotlib import pyplot as plt

from evolute import GeneticPopulation
from evolute.evaluation import SimpleFitness


def fitness(ind, target):
    return np.linalg.norm(target - ind)


def main():
    TARGET = np.array([3., 3.])

    pop = GeneticPopulation(
        loci=2,
        fitness_wrapper=SimpleFitness(fitness, constants={"target": TARGET}),
        limit=100)

    plt.ion()
    obj = plt.plot(*pop.individuals.T, "bo", markersize=2)[0]
    plt.xlim([-2, 11])
    plt.ylim([-2, 11])

    X, Y = np.linspace(-2, 11, 50), np.linspace(-2, 11, 50)
    X, Y = np.meshgrid(X, Y)
    Z = np.array([fitness(np.array([x, y]), target=TARGET)
                  for x, y in zip(X.ravel(), Y.ravel())]).reshape(X.shape)
    CS = plt.contour(X, Y, Z, cmap="hot")
    plt.clabel(CS, inline=1, fontsize=10)
    title_template = "Best: [{:.4f}, {:.4f}], G: {:.4f}"
    title_obj = plt.title(title_template.format(0., 0., 0.))
    plt.show()
    means, stds, bests = [], [], []
    for i in range(30):
        pop.epoch(force_update=True, verbosity=0)
        means.append(pop.fitnesses.mean())
        stds.append(pop.fitnesses.std())
        bests.append(pop.fitnesses.min())
        obj.set_data(*pop.individuals.T)
        title_obj.set_text(title_template.format(*pop.get_best(), pop.fitnesses.min()))
        plt.pause(0.1)

    means, stds, bests = tuple(map(np.array, (means, stds, bests)))
    plt.close()
    plt.ioff()
    Xs = np.arange(1, len(means) + 1)
    plt.plot(Xs, means, "b-", label="mean")
    plt.plot(Xs, means+stds, "g--", label="stdev")
    plt.plot(Xs, means-stds, "g--")
    plt.plot(Xs, bests, "r-", label="best")
    plt.xlim([Xs.min()-1, Xs.max()+1])
    plt.ylim([bests.min()-1, (means+stds).max()+1])
    plt.legend()
    plt.grid()
    plt.show()


if __name__ == '__main__':
    main()


================================================
FILE: examples/xp_simple.py
================================================
import numpy as np

from matplotlib import pyplot as plt

from evolute import GeneticPopulation
from evolute.evaluation import SimpleFitness

TARGET = np.ones(10) * 0.5

pop = GeneticPopulation(loci=10,
                        fitness_wrapper=SimpleFitness(lambda ind: np.linalg.norm(ind - TARGET)))

history = pop.run(100)
history = {k: np.array(v) for k, v in history.history.items()}

x = history["generation"]

plt.plot(x, history["mean_grade"], "r-", label="mean")
plt.plot(x, history["mean_grade"] + history["grade_std"], "b--", label="std")
plt.plot(x, history["mean_grade"] - history["grade_std"], "b--")
plt.plot(x, history["best_grade"], "g-", label="mean")

plt.title("Population convergence")
plt.legend()
plt.grid()
plt.show()


================================================
FILE: requirements.txt
================================================
numpy

================================================
FILE: setup.py
================================================
from setuptools import setup, find_packages

setup(
    name='evolute',
    version='0.9.0',
    packages=find_packages(),
    url='https://github.com/csxeba/evolute.git',
    license='MIT',
    author='Csaba Gór',
    author_email='csxeba@gmail.com',
    description='Evolutionary algorithm toolbox',
    long_description=open("Readme.md").read(),
    long_description_content_type='text/markdown'
)


================================================
FILE: tests/test_evaluation.py
================================================
import unittest

import numpy as np

from evolute.evaluation import WeightedSumGrader


class TestGrade(unittest.TestCase):

    def setUp(self):
        self.sample_fitness_vector = np.ones(3)
        self.sample_fitness_weigts = np.ones(3) + 1

    def test_weighted_sum_grader(self):
        grader = WeightedSumGrader(weights=self.sample_fitness_weigts)
        calced = grader(self.sample_fitness_vector)
        self.assertEqual(calced, self.sample_fitness_vector @ self.sample_fitness_weigts)


================================================
FILE: tests/test_operator.py
================================================
import unittest

import numpy as np

from evolute.operators import SmoothMate, RandomPickMate
from evolute.operators import UniformLocuswiseMutation
from evolute.operators import Elitism


class TestMate(unittest.TestCase):

    def setUp(self):
        self.sample_individuals = [
            np.zeros(3), np.ones(3) + 1
        ]

    def test_random_pick_mated_offspring_only_contains_entries_from_parents(self):
        mater = RandomPickMate()
        offspring = mater(*self.sample_individuals)
        eq = np.logical_or(offspring == 0., offspring == 2.)
        self.assertTrue(np.all(eq))

    def test_smooth_mate_produces_offspring_which_is_the_mean_of_parents(self):
        mater = SmoothMate()
        offspring = mater(*self.sample_individuals)
        self.assertTrue(np.all(offspring == np.ones_like(offspring)))


class TestMutate(unittest.TestCase):

    def setUp(self):
        self.sample_individuals = np.zeros((3, 4))

    def test_uniform_locuswise_op_mutates_every_locus_with_rate_1(self):
        # Test may fail in the very unlikely case of a mutation perturbance element being exactly 0.
        mutator = UniformLocuswiseMutation(rate=1.)
        mutant = mutator(self.sample_individuals)
        self.assertFalse(np.all(mutant == self.sample_individuals))


class TestSelection(unittest.TestCase):

    def setUp(self):
        self.sample_individuals = np.stack([np.zeros(3)]*9 + [np.ones(3) + 1.], axis=0)
        self.sample_grades = np.arange(len(self.sample_individuals), 0, -1)

    def test_number_of_selected_individuals_corresponds_to_set_selection_rate(self):
        rate = 0.5
        selector = Elitism(selection_rate=rate)
        selector(self.sample_individuals, self.sample_grades)
        self.assertEqual(selector.mask.sum(), rate * len(self.sample_individuals))

    def test_elitism_with_an_engineered_population(self):
        rate = 0.8
        no_offsprings = int(rate * 10)

        selector = Elitism(selection_rate=rate, mate_op=SmoothMate(), exclude_self_mating=True)
        offspring = selector(self.sample_individuals, self.sample_grades, inplace=False)
        self.assertTrue(np.all(offspring[:no_offsprings] == 1.))
Download .txt
gitextract_mywosglh/

├── .gitignore
├── LICENSE
├── Readme.md
├── evolute/
│   ├── __init__.py
│   ├── evaluation/
│   │   ├── __init__.py
│   │   ├── fitness.py
│   │   └── grade.py
│   ├── initialization/
│   │   ├── __init__.py
│   │   └── initializer.py
│   ├── operators/
│   │   ├── __init__.py
│   │   ├── mate.py
│   │   ├── mutate.py
│   │   ├── operators.py
│   │   └── selection.py
│   ├── population/
│   │   ├── __init__.py
│   │   ├── genetic.py
│   │   └── population.py
│   └── utility/
│       ├── __init__.py
│       ├── describe.py
│       ├── history.py
│       ├── keras_utility.py
│       └── test_utils.py
├── examples/
│   ├── xp_evolve_net.py
│   ├── xp_keras.py
│   ├── xp_quadratic.py
│   └── xp_simple.py
├── requirements.txt
├── setup.py
└── tests/
    ├── test_evaluation.py
    └── test_operator.py
Download .txt
SYMBOL INDEX (124 symbols across 18 files)

FILE: evolute/evaluation/fitness.py
  class FitnessBase (line 6) | class FitnessBase:
    method __init__ (line 8) | def __init__(self, no_fitnesses):
    method __call__ (line 11) | def __call__(self, phenotype):
  class SimpleFitness (line 15) | class SimpleFitness(FitnessBase):
    method __init__ (line 17) | def __init__(self, fitness_function, constants: dict=None, **kw):
    method __call__ (line 23) | def __call__(self, phenotype, **variables):
  class MultipleFitnesses (line 27) | class MultipleFitnesses(FitnessBase):
    method __init__ (line 29) | def __init__(self, functions_by_name, constants_by_function_name=None,...
    method __call__ (line 42) | def __call__(self, phenotype, **variables_by_function):
  class MultiReturnFitness (line 49) | class MultiReturnFitness(FitnessBase):
    method __init__ (line 51) | def __init__(self, fitness_function, number_of_return_values, constant...
    method __call__ (line 57) | def __call__(self, phenotype, **variables):

FILE: evolute/evaluation/grade.py
  class GraderBase (line 4) | class GraderBase:
    method __call__ (line 6) | def __call__(self, fitness):
  class SumGrader (line 10) | class SumGrader(GraderBase):
    method __call__ (line 12) | def __call__(self, fitness):
  class WeightedSumGrader (line 16) | class WeightedSumGrader(GraderBase):
    method __init__ (line 18) | def __init__(self, weights):
    method __call__ (line 21) | def __call__(self, fitness):

FILE: evolute/initialization/initializer.py
  class Initializer (line 4) | class Initializer:
    method initialize (line 6) | def initialize(self, *shape):
  class NormalRandom (line 10) | class NormalRandom(Initializer):
    method __init__ (line 12) | def __init__(self, mean=0., stdev=1.):
    method initialize (line 16) | def initialize(self, *shape):
  class UniformRandom (line 20) | class UniformRandom(Initializer):
    method __init__ (line 22) | def __init__(self, low=-1, high=1.):
    method initialize (line 26) | def initialize(self, *shape):
  class OrthogonalNormal (line 30) | class OrthogonalNormal(Initializer):
    method initialize (line 32) | def initialize(self, *shape):

FILE: evolute/operators/mate.py
  class MateBase (line 4) | class MateBase:
    method apply (line 6) | def apply(self, ind1, ind2):
    method __call__ (line 9) | def __call__(self, ind1, ind2):
  class LambdaMate (line 13) | class LambdaMate(MateBase):
    method __init__ (line 15) | def __init__(self, function_ref, **kw):
  class RandomPickMate (line 20) | class RandomPickMate(MateBase):
    method apply (line 22) | def apply(self, ind1, ind2):
  class SmoothMate (line 26) | class SmoothMate(MateBase):
    method apply (line 28) | def apply(self, ind1, ind2):
  class ScatterMateWrapper (line 35) | class ScatterMateWrapper(MateBase):
    method __init__ (line 37) | def __init__(self, base=DefaultMate, stdev=1.):
    method apply (line 43) | def apply(self, ind1, ind2):

FILE: evolute/operators/mutate.py
  class MutationBase (line 4) | class MutationBase:
    method __init__ (line 6) | def __init__(self, rate=0.1):
    method set_rate (line 10) | def set_rate(self, rate):
    method apply (line 15) | def apply(self, individuals, inplace=False):
    method __call__ (line 18) | def __call__(self, individuals, inplace=False):
  class UniformLocuswiseMutation (line 22) | class UniformLocuswiseMutation(MutationBase):
    method __init__ (line 24) | def __init__(self, rate=0.1, low=-1., high=1.):
    method set_params (line 29) | def set_params(self, low=None, high=None):
    method apply (line 33) | def apply(self, individuals, inplace=False):
  class NormalIndividualwiseMutation (line 51) | class NormalIndividualwiseMutation(MutationBase):
    method __init__ (line 53) | def __init__(self, rate=0.1, stdev=1.):
    method set_param (line 57) | def set_param(self, stdev):
    method apply (line 60) | def apply(self, individuals, inplace=False):

FILE: evolute/operators/operators.py
  class Operators (line 5) | class Operators:
    method __init__ (line 7) | def __init__(self, selection_op=None, mutate_op=None, mate_op=None):
    method _clarify_mate_operator (line 12) | def _clarify_mate_operator(self, mate_op):
    method invalid_individual_indices (line 26) | def invalid_individual_indices(self):

FILE: evolute/operators/selection.py
  class SelectionBase (line 4) | class SelectionBase:
    method __init__ (line 6) | def __init__(self, selection_rate=0.5, mate_op=None, exclude_self_mati...
    method mask (line 14) | def mask(self):
    method set_mate_operator (line 17) | def set_mate_operator(self, mate_op):
    method _stream_of_parent_indices (line 20) | def _stream_of_parent_indices(self):
    method set_survival_rate (line 39) | def set_survival_rate(self, survival_rate):
    method set_selection_rate (line 44) | def set_selection_rate(self, selection_rate):
    method apply (line 49) | def apply(self, individuals, fitnesses, inplace=False):
    method __call__ (line 52) | def __call__(self, individuals, fitnesses, inplace=False):
  class Elitism (line 56) | class Elitism(SelectionBase):
    method apply (line 58) | def apply(self, individuals, fitnesses, inplace=False):
    method _selection_step (line 64) | def _selection_step(self, individuals, grades):
    method _reproduction_inplace (line 72) | def _reproduction_inplace(self, individuals):
    method _reproduction_copy (line 78) | def _reproduction_copy(self, individuals):

FILE: evolute/population/genetic.py
  class GeneticPopulation (line 4) | class GeneticPopulation(Population):
    method update_individual (line 6) | def update_individual(self, index, **fitness_kw):

FILE: evolute/population/population.py
  class Population (line 9) | class Population:
    method __init__ (line 11) | def __init__(self, loci: int,
    method simple_fitness (line 37) | def simple_fitness(cls, fitness_callback,
    method get_individual (line 46) | def get_individual(self, index):
    method set_individual (line 49) | def set_individual(self, index, individual):
    method get_best (line 52) | def get_best(self):
    method get_champion (line 55) | def get_champion(self):
    method get_fitness_weighted_average_individual (line 58) | def get_fitness_weighted_average_individual(self):
    method run (line 62) | def run(self, epochs: int,
    method epoch (line 96) | def epoch(self, force_update=False, verbosity=1, **fitness_kw):
    method _initialize (line 105) | def _initialize(self, verbosity, **fitness_kw):
    method update (line 115) | def update(self, forced=False, verbose=0, **fitness_kw):
    method update_individual (line 128) | def update_individual(self, index, **fitness_kw):
    method _invalidated_individual_indices (line 131) | def _invalidated_individual_indices(self, force_update):
    method save (line 134) | def save(self, path):
    method load (line 141) | def load(path):

FILE: evolute/utility/describe.py
  function describe (line 4) | def describe(population, show=0):

FILE: evolute/utility/history.py
  class History (line 1) | class History:
    method __init__ (line 3) | def __init__(self, aspects=()):
    method record (line 6) | def record(self, data):
    method __getitem__ (line 10) | def __getitem__(self, item):

FILE: evolute/utility/keras_utility.py
  function get_keras_weights (line 4) | def get_keras_weights(model, folded=False):
  function get_keras_number_of_trainables (line 11) | def get_keras_number_of_trainables(model):
  class WeightFolding (line 15) | class WeightFolding:
    method __init__ (line 17) | def __init__(self, model):
    method __call__ (line 21) | def __call__(self, individual):

FILE: evolute/utility/test_utils.py
  function is_standardish (line 4) | def is_standardish(array, globally=False, epsilon=1e-7):
  function is_normalish (line 10) | def is_normalish(array, epsilon=1e-7):

FILE: examples/xp_evolve_net.py
  function fitness (line 31) | def fitness(phenotype, layerstack, X, Y):
  function forge_layerstack (line 36) | def forge_layerstack():
  function get_population (line 44) | def get_population():
  function xperiment (line 54) | def xperiment():

FILE: examples/xp_keras.py
  function pull_mnist (line 15) | def pull_mnist():
  function fitness_callback (line 23) | def fitness_callback(phenotype, model: Sequential, w_folder, X, Y):

FILE: examples/xp_quadratic.py
  function fitness (line 8) | def fitness(ind, target):
  function main (line 12) | def main():

FILE: tests/test_evaluation.py
  class TestGrade (line 8) | class TestGrade(unittest.TestCase):
    method setUp (line 10) | def setUp(self):
    method test_weighted_sum_grader (line 14) | def test_weighted_sum_grader(self):

FILE: tests/test_operator.py
  class TestMate (line 10) | class TestMate(unittest.TestCase):
    method setUp (line 12) | def setUp(self):
    method test_random_pick_mated_offspring_only_contains_entries_from_parents (line 17) | def test_random_pick_mated_offspring_only_contains_entries_from_parent...
    method test_smooth_mate_produces_offspring_which_is_the_mean_of_parents (line 23) | def test_smooth_mate_produces_offspring_which_is_the_mean_of_parents(s...
  class TestMutate (line 29) | class TestMutate(unittest.TestCase):
    method setUp (line 31) | def setUp(self):
    method test_uniform_locuswise_op_mutates_every_locus_with_rate_1 (line 34) | def test_uniform_locuswise_op_mutates_every_locus_with_rate_1(self):
  class TestSelection (line 41) | class TestSelection(unittest.TestCase):
    method setUp (line 43) | def setUp(self):
    method test_number_of_selected_individuals_corresponds_to_set_selection_rate (line 47) | def test_number_of_selected_individuals_corresponds_to_set_selection_r...
    method test_elitism_with_an_engineered_population (line 53) | def test_elitism_with_an_engineered_population(self):
Condensed preview — 30 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (45K chars).
[
  {
    "path": ".gitignore",
    "chars": 797,
    "preview": "# Created by .ignore support plugin (hsz.mobi)\n### Python template\n# Byte-compiled / optimized / DLL files\n__pycache__/\n"
  },
  {
    "path": "LICENSE",
    "chars": 1066,
    "preview": "MIT License\n\nCopyright (c) 2018 Csaba Gor\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n"
  },
  {
    "path": "Readme.md",
    "chars": 9348,
    "preview": "[![codebeat badge](https://codebeat.co/badges/f72db301-fd66-4c05-b1ca-9b8c8196f06e)](https://codebeat.co/projects/github"
  },
  {
    "path": "evolute/__init__.py",
    "chars": 42,
    "preview": "from .population import GeneticPopulation\n"
  },
  {
    "path": "evolute/evaluation/__init__.py",
    "chars": 147,
    "preview": "from .fitness import FitnessBase, SimpleFitness, MultipleFitnesses, MultiReturnFitness\nfrom .grade import GraderBase, Su"
  },
  {
    "path": "evolute/evaluation/fitness.py",
    "chars": 2401,
    "preview": "import numpy as np\n\nfrom .grade import SumGrader\n\n\nclass FitnessBase:\n\n    def __init__(self, no_fitnesses):\n        sel"
  },
  {
    "path": "evolute/evaluation/grade.py",
    "chars": 421,
    "preview": "import numpy as np\n\n\nclass GraderBase:\n\n    def __call__(self, fitness):\n        raise NotImplementedError\n\n\nclass SumGr"
  },
  {
    "path": "evolute/initialization/__init__.py",
    "chars": 106,
    "preview": "from .initializer import NormalRandom, UniformRandom, OrthogonalNormal\n\nDefaultInitializer = NormalRandom\n"
  },
  {
    "path": "evolute/initialization/initializer.py",
    "chars": 841,
    "preview": "import numpy as np\n\n\nclass Initializer:\n\n    def initialize(self, *shape):\n        raise NotImplementedError\n\n\nclass Nor"
  },
  {
    "path": "evolute/operators/__init__.py",
    "chars": 262,
    "preview": "from .mate import DefaultMate, LambdaMate, SmoothMate, RandomPickMate, ScatterMateWrapper\nfrom .mutate import DefaultMut"
  },
  {
    "path": "evolute/operators/mate.py",
    "chars": 944,
    "preview": "import numpy as np\n\n\nclass MateBase:\n\n    def apply(self, ind1, ind2):\n        pass\n\n    def __call__(self, ind1, ind2):"
  },
  {
    "path": "evolute/operators/mutate.py",
    "chars": 2115,
    "preview": "import numpy as np\n\n\nclass MutationBase:\n\n    def __init__(self, rate=0.1):\n        self.rate = rate\n        self.mask ="
  },
  {
    "path": "evolute/operators/operators.py",
    "chars": 1148,
    "preview": "import numpy as np\nfrom . import DefaultSelection, DefaultMutate, DefaultMate\n\n\nclass Operators:\n\n    def __init__(self,"
  },
  {
    "path": "evolute/operators/selection.py",
    "chars": 3023,
    "preview": "import numpy as np\n\n\nclass SelectionBase:\n\n    def __init__(self, selection_rate=0.5, mate_op=None, exclude_self_mating="
  },
  {
    "path": "evolute/population/__init__.py",
    "chars": 74,
    "preview": "from .population import Population\nfrom .genetic import GeneticPopulation\n"
  },
  {
    "path": "evolute/population/genetic.py",
    "chars": 216,
    "preview": "from .population import Population\n\n\nclass GeneticPopulation(Population):\n\n    def update_individual(self, index, **fitn"
  },
  {
    "path": "evolute/population/population.py",
    "chars": 5785,
    "preview": "import numpy as np\n\nfrom ..initialization import DefaultInitializer\nfrom ..operators import Operators\nfrom ..evaluation "
  },
  {
    "path": "evolute/utility/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "evolute/utility/describe.py",
    "chars": 1016,
    "preview": "import numpy as np\n\n\ndef describe(population, show=0):\n    showme = np.argsort(population.grades)[:show]\n    chain = \"-\""
  },
  {
    "path": "evolute/utility/history.py",
    "chars": 303,
    "preview": "class History:\n\n    def __init__(self, aspects=()):\n        self.history = {aspect: [] for aspect in [\"generation\"] + li"
  },
  {
    "path": "evolute/utility/keras_utility.py",
    "chars": 762,
    "preview": "import numpy as np\n\n\ndef get_keras_weights(model, folded=False):\n    w_tensors = model.trainable_weights\n    if folded:\n"
  },
  {
    "path": "evolute/utility/test_utils.py",
    "chars": 429,
    "preview": "import numpy as np\n\n\ndef is_standardish(array, globally=False, epsilon=1e-7):\n    if globally:\n        return np.allclos"
  },
  {
    "path": "examples/xp_evolve_net.py",
    "chars": 2449,
    "preview": "import numpy as np\n\nfrom matplotlib import pyplot as plt\n\nfrom brainforge import LayerStack\nfrom brainforge.layers impor"
  },
  {
    "path": "examples/xp_keras.py",
    "chars": 2247,
    "preview": "import numpy as np\n\nfrom keras.layers import Dense\nfrom keras.models import Sequential\nfrom keras.datasets import mnist\n"
  },
  {
    "path": "examples/xp_quadratic.py",
    "chars": 1840,
    "preview": "import numpy as np\nfrom matplotlib import pyplot as plt\n\nfrom evolute import GeneticPopulation\nfrom evolute.evaluation i"
  },
  {
    "path": "examples/xp_simple.py",
    "chars": 740,
    "preview": "import numpy as np\n\nfrom matplotlib import pyplot as plt\n\nfrom evolute import GeneticPopulation\nfrom evolute.evaluation "
  },
  {
    "path": "requirements.txt",
    "chars": 5,
    "preview": "numpy"
  },
  {
    "path": "setup.py",
    "chars": 401,
    "preview": "from setuptools import setup, find_packages\n\nsetup(\n    name='evolute',\n    version='0.9.0',\n    packages=find_packages("
  },
  {
    "path": "tests/test_evaluation.py",
    "chars": 500,
    "preview": "import unittest\n\nimport numpy as np\n\nfrom evolute.evaluation import WeightedSumGrader\n\n\nclass TestGrade(unittest.TestCas"
  },
  {
    "path": "tests/test_operator.py",
    "chars": 2181,
    "preview": "import unittest\n\nimport numpy as np\n\nfrom evolute.operators import SmoothMate, RandomPickMate\nfrom evolute.operators imp"
  }
]

About this extraction

This page contains the full source code of the csxeba/evolute GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 30 files (40.6 KB), approximately 10.7k tokens, and a symbol index with 124 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!