"""A collection of functions allowing genetics manipulations."""

from xentica import core
from xentica.tools import xmath


def genome_crossover(state, num_genes, *genomes,
                     mutation_prob=0, rng_name="rng"):
    """
    Crossover given genomes in stochastic way.

    :param state:
        A container holding model's properties.
    :param num_genes:
        Genome length, assuming all genomes has same number of genes.
    :param genomes:
        A list of genomes (integers) to crossover
    :param mutation_prob:
        Probability of single gene mutation.
    :param rng_name:
        Name of ``RandomProperty``.

    :returns: Single integer, a resulting genome.

    """
    gene_choose = core.IntegerVariable()
    new_genome = core.IntegerVariable()
    num_genomes = core.IntegerVariable()
    for gene in range(num_genes):
        gene_choose *= 0
        num_genomes *= 0
        for genome in genomes:
            gene_choose += ((genome >> gene) & 1 & (genome > 0)) << num_genomes
            num_genomes += (genome > 0)
        rand_val = getattr(state, rng_name).uniform
        winner_gene = xmath.int(rand_val * num_genomes)
        new_gene = ((gene_choose >> winner_gene) & 1)
        is_mutated = 0
        if mutation_prob > 0:
            is_mutated = getattr(state, rng_name).uniform < mutation_prob
            is_mutated = is_mutated * (gene_choose > 0)
        new_genome += (new_gene ^ is_mutated) << gene
    return new_genome

@@ -166,17 +166,33 @@
 genomes,
+ max_genes=None,
 %0A
-
         
@@ -522,16 +522,93 @@
 ossover%0A
+    :param max_genes:%0A        Upper limit for '1' genes in resulting genome.%0A
     :par
@@ -905,24 +905,309 @@
 rVariable()%0A
+    if max_genes is not None:%0A        num_active = core.IntegerVariable()%0A    new_gene = core.IntegerVariable()%0A    rand_val = getattr(state, rng_name).uniform%0A    start_gene = core.IntegerVariable()%0A    start_gene *= 0%0A    start_gene += xmath.int(rand_val * num_genes) %25 len(genomes)%0A
     for gene
@@ -1274,24 +1274,71 @@
 enomes *= 0%0A
+        gene = (gene + start_gene) %25 num_genes%0A
         for 
@@ -1601,16 +1601,39 @@
 ew_gene 
+*= 0%0A        new_gene +
 = ((gene
@@ -1661,16 +1661,133 @@
 e) & 1)%0A
+        if max_genes is not None:%0A            num_active += new_gene%0A            new_gene *= num_active %3C= max_genes%0A
         

Add max genes limit to genome crossover (#55)