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
================================================
[](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.))
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
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": "[](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.