Source code for alogos.systems.dsge.crossover

"""Crossover functions for DSGE."""

import random as _random

from ..._utilities.parametrization import get_given_or_default as _get_given_or_default
from . import default_parameters as _default_parameters
from . import repair as _repair
from . import representation as _representation


# Shortcuts for minor speedup
_GT = _representation.Genotype
_rc = _random.choice


[docs]def gene_swap(grammar, genotype1, genotype2, parameters=None): """Generate new DSGE genotypes by exchanging a random gene. Each DSGE genotype contains the same number of genes. Randomly select one gene and exchange it between the two genotypes. Parameters ---------- grammar : `~alogos.Grammar` genotype1 : `~.representation.Genotype` Genotype of the first parent. genotype2 : `~.representation.Genotype` Genotype of the second parent. parameters : `dict` or `~alogos._utilities.parametrization.ParameterCollection`, optional Following keyword-value pairs are considered by this function: - ``repair_after_crossover`` (`bool`): {`True`, `False`} Returns ------- genotype1 : `~.representation.Genotype` Genotype of the first child. genotype2 : `~.representation.Genotype` Genotype of the second child. References ---------- - Software implementations by the authors of the approach - Python: `dsge <https://github.com/nunolourenco/dsge>`__ - `core/sge.py <https://github.com/nunolourenco/dsge/blob/master/src/core/sge.py>`__: ``def crossover(p1, p2)`` is the implementation of the crossover operator - Papers - Lourenço et al. in 2018: `Structured Grammatical Evolution: A Dynamic Approach <https://doi.org/10.1007/978-3-319-78717-6_6>`__ - p. 145: "It starts by creating a random binary mask and the offspring are created by selecting the parents genes based on the mask values. Recombination does not modify the lists inside the genes. This is similar to what happens with uniform crossover for binary representations." """ # Parameter extraction repair = _get_given_or_default( "repair_after_crossover", parameters, _default_parameters ) # Argument processing if not isinstance(genotype1, _GT): genotype1 = _GT(genotype1) if not isinstance(genotype2, _GT): genotype2 = _GT(genotype2) # Crossover: For each position use the gene of one parent according to a random binary mask d1 = genotype1.data d2 = genotype2.data vals = (True, False) mask = [_rc(vals) for _ in range(len(d1))] n1 = tuple(d1[i] if x else d2[i] for i, x in enumerate(mask)) n2 = tuple(d2[i] if x else d1[i] for i, x in enumerate(mask)) # Optional repair of the new genotypes (either here and/or later) if repair: gt1 = _repair.fix_genotype(grammar, n1, parameters, raise_errors=False) gt2 = _repair.fix_genotype(grammar, n2, parameters, raise_errors=False) else: gt1 = _GT(n1) gt2 = _GT(n2) return gt1, gt2