示例#1
0
    def absorb(self):
        """Absorb an energy from neighbors."""
        # absorb incoming energy and calculate 'birthing' status
        incoming_energy = core.IntegerVariable()
        num_full = core.IntegerVariable()
        treshold = self.meta.full_treshold
        for i in range(len(self.buffers)):
            incoming_energy += self.neighbors[i].buffer.energy
            is_full = self.neighbors[i].main.new_energy >= treshold
            num_full += is_full

        self.main.energy = self.main.new_energy + incoming_energy
        self.main.birthing = self.main.rule.is_born(num_full)
        self.main.birthing *= self.main.energy < self.meta.full_treshold

        # neighbor's genomes crossover
        genomes = []
        for i in range(len(self.buffers)):
            genomes.append(core.IntegerVariable(name="genome%d" % i))
        for i in range(len(self.buffers)):
            is_fit = self.neighbors[i].buffer.energy > 0
            is_fit = is_fit * (self.neighbors[i].buffer.rule > 0)
            genomes[i] += self.neighbors[i].buffer.rule * is_fit
        num_genes = self.main.rule.bit_width
        new_genome = genome_crossover(
            self.main,
            num_genes,
            *genomes,
            max_genes=self.meta.max_genes,
            mutation_prob=self.meta.mutation_prob) * (self.main.energy <
                                                      self.meta.full_treshold)
        self.main.rule = new_genome + self.main.rule * (new_genome == 0)
示例#2
0
    def absorb(self):
        """Apply EvoLife dynamics."""
        # test if cell is sustained
        num_neighbors = core.IntegerVariable()
        for i in range(len(self.buffers)):
            nbr_energy = self.neighbors[i].buffer.energy
            nbr_rule = self.neighbors[i].buffer.rule
            num_neighbors += xmath.min(1, (nbr_energy + nbr_rule))
        is_sustained = core.IntegerVariable()
        is_sustained += self.main.rule.is_sustained(num_neighbors)

        # test if cell is born
        fitnesses = []
        for i in range(len(self.buffers)):
            fitnesses.append(core.IntegerVariable(name="fit%d" % i))
        num_parents = core.IntegerVariable()
        for gene in range(len(self.buffers)):
            num_parents *= 0  # hack for re-init variable
            for i in range(len(self.buffers)):
                nbr_energy = self.neighbors[i].buffer.energy
                nbr_rule = self.neighbors[i].buffer.rule
                is_alive = xmath.min(1, (nbr_energy + nbr_rule))
                is_fit = self.neighbors[i].buffer.rule.is_born(gene + 1)
                num_parents += is_alive * is_fit
            fitnesses[gene] += num_parents * (num_parents == (gene + 1))
        num_fit = core.IntegerVariable()
        num_fit += xmath.max(*fitnesses)

        # neighbor's genomes crossover
        genomes = []
        for i in range(len(self.buffers)):
            genomes.append(core.IntegerVariable(name="genome%d" % i))
        for i in range(len(self.buffers)):
            is_fit = self.neighbors[i].buffer.rule.is_born(num_fit)
            genomes[i] += self.neighbors[i].buffer.rule * is_fit
        num_genes = self.main.rule.bit_width
        old_rule = core.IntegerVariable()
        old_rule += self.main.rule
        old_energy = core.IntegerVariable()
        old_energy += self.main.energy
        new_genome = genome_crossover(
            self.main, num_genes, *genomes,
            max_genes=self.meta.max_genes,
            mutation_prob=self.meta.mutation_prob
        )
        self.main.rule = new_genome + self.main.rule * (new_genome == 0)

        # new energy value
        self.main.energy *= 0
        is_live = core.IntegerVariable()
        old_live = (old_energy + old_rule) == 0
        is_live += (old_energy < 0xff) & (old_live | is_sustained)
        old_dead = (old_energy + old_rule) != 0
        new_energy = old_energy + self.meta.death_speed * old_dead
        self.main.energy = new_energy * (self.main.rule == old_rule) + \
            self.main.energy * (self.main.rule != old_rule)
        self.main.rule = old_rule * (self.main.rule == old_rule) + \
            self.main.rule * (self.main.rule != old_rule)
        self.main.energy *= is_live
        self.main.rule *= is_live
示例#3
0
    def emit(self):
        """Apply ConcervedLife dynamics."""
        self.main.new_energy = 1 * self.main.energy

        # calculate number of full neighbors
        num_full = core.IntegerVariable()
        for i in range(len(self.buffers)):
            is_full = self.neighbors[i].main.energy >= self.meta.full_treshold
            num_full += is_full

        # decide, do cell need to spread an energy
        me_full = self.main.energy >= self.meta.full_treshold
        me_empty = self.main.energy < self.meta.full_treshold
        me_dying = xmath.int(self.main.rule.is_sustained(num_full)) == 0
        me_dying = xmath.int(me_dying)
        me_birthing = self.main.rule.is_born(num_full)
        has_free_energy = self.main.energy > self.meta.full_treshold
        has_free_energy = xmath.int(has_free_energy)
        need_spread_full = 1 * me_full * (has_free_energy | me_dying)
        need_spread_empty = 1 * me_empty * (xmath.int(me_birthing) == 0)
        need_spread = need_spread_full + need_spread_empty

        # search the direction to spread energy
        denergy = core.IntegerVariable()
        energy_passed = core.IntegerVariable()
        energy_passed *= 1
        gate = core.IntegerVariable()
        gate += xmath.int(self.main.rng.uniform * 8)
        gate_final = core.IntegerVariable()
        treshold = self.meta.full_treshold
        for i in range(len(self.buffers) * 3):
            i_valid = (i >= gate) * (i < gate + len(self.buffers) * 2)
            is_birthing = self.neighbors[i % 8].main.birthing * (i < 8 + gate)
            is_empty = self.neighbors[i % 8].main.energy < treshold
            is_empty = is_empty * (i >= 8 + gate)
            is_fit = is_empty + is_birthing
            denergy *= 0
            denergy += xmath.min(self.main.new_energy, self.meta.death_speed)
            denergy *= need_spread * is_fit * (energy_passed == 0)
            denergy *= i_valid
            gate_final *= (energy_passed != 0)
            gate_final += (i % 8) * (energy_passed == 0)
            energy_passed += denergy

        # spread the energy in chosen direction
        for i in range(len(self.buffers)):
            gate_fit = i == gate_final
            self.buffers[i].energy = energy_passed * gate_fit
            self.buffers[i].rule = self.main.rule * gate_fit

        self.main.new_energy -= energy_passed
示例#4
0
    def absorb(self):
        """
        Implement the logic of absorb phase.

        Each cell just sums incoming energy and gate values.

        """
        incoming_energy = core.IntegerVariable()
        incoming_gate = core.IntegerVariable()
        for i in range(len(self.buffers)):
            incoming_energy += self.neighbors[i].buffer.energy
            incoming_gate += self.neighbors[i].buffer.gate
        self.main.energy += incoming_energy
        self.main.gate += incoming_gate % 8
示例#5
0
    def emit(self):
        """
        Implement the logic of emit phase.

        Each cell is a Poisson process that fires an energy in the
        gate direction, when Poisson event occurs.

        The rate of events depends on cell's energy level: more
        energy, higher the rate.

        The amount of energy depends on the cell's own "valency" and
        its gated neighbour's "valency" (energy % 8).

        When neighbour's valency is 0, cell spreads the amount of
        energy, equal to its own valency. Otherwise, it spreads some
        default amount of energy.

        Cells are also spreading their gate values when event occurs,
        so they are "syncing" with neighbours.

        """
        shade = xmath.min(255, self.main.energy)
        lmb = xmath.float(self.main.interval) / xmath.float(256 - shade)
        prob = 1 - xmath.exp(-lmb)
        fired = core.IntegerVariable()
        fired += xmath.int(self.main.rng.uniform < prob)
        fired *= self.main.energy > 0
        denergy = xmath.min(self.default_denergy, shade)
        gate = self.main.gate

        mutated = core.IntegerVariable()
        mutated += xmath.int(self.main.rng.uniform < 0.0001)
        denergy = denergy - 1 * (denergy > 0) * mutated
        energy_passed = core.IntegerVariable()
        for i in range(len(self.buffers)):
            valency1 = self.neighbors[i].main.energy % 8
            valency2 = self.main.energy % 8
            gate_fit = (i == gate)
            full_transition = denergy * (valency1 != 0 | valency2 == 0)
            potent_transition = valency2 * (valency1 == 0)
            denergy_fin = full_transition + potent_transition
            energy_passed += denergy_fin * fired * gate_fit
            self.buffers[i].energy = energy_passed * fired * gate_fit
            self.buffers[i].gate = (self.main.gate + 7) * fired * gate_fit

        self.main.interval = (self.main.interval + 1) * (energy_passed == 0)
        self.main.energy -= energy_passed * (energy_passed > 0)
        self.main.gate = (self.main.gate + 1) % 8
示例#6
0
 def absorb(self):
     """Implement parent's clone with a rule as a parameter."""
     neighbors_alive = core.IntegerVariable()
     for i in range(len(self.buffers)):
         neighbors_alive += self.neighbors[i].buffer.state
     is_born = (self.rule >> neighbors_alive) & 1
     is_sustain = (self.rule >> 9 >> neighbors_alive) & 1
     self.main.state = is_born | is_sustain & self.main.state
示例#7
0
    def absorb(self):
        """
        Calculate RGB as neighbors sum for living cell only.

        Note, parent ``absorb`` method should be called using direct
        class access, not via ``super``.

        """
        GameOfLife.absorb(self)
        red_sum = core.IntegerVariable()
        green_sum = core.IntegerVariable()
        blue_sum = core.IntegerVariable()
        for i in range(len(self.buffers)):
            red_sum += self.neighbors[i].buffer.red + 1
            green_sum += self.neighbors[i].buffer.green + 1
            blue_sum += self.neighbors[i].buffer.blue + 1
        self.main.red = red_sum * self.main.state
        self.main.green = green_sum * self.main.state
        self.main.blue = blue_sum * self.main.state
示例#8
0
def hsv2rgb(hue, saturation, value):
    """
    Convert HSV color to RGB format.

    :param hue: Hue value [0, 1]
    :param saturation: Saturation value [0, 1]
    :param value: Brightness value [0, 1]

    :returns: tuple (red, green, blue)

    """
    if isinstance(hue, DeferredExpression):
        hue_f = core.FloatVariable()
        hue_f += hue * 6
        hue_i = core.IntegerVariable()
        hue_i += xmath.int(hue_f)
        hue_f -= hue_i
        sat = core.FloatVariable()
        sat += saturation
        val = core.FloatVariable()
        val += value
        grad_p = core.FloatVariable()
        grad_p += val * (1 - sat)
        grad_q = core.FloatVariable()
        grad_q += val * (1 - sat * hue_f)
        grad_t = core.FloatVariable()
        grad_t += val * (1 - sat * (1 - hue_f))
    else:
        hue_f = hue * 6
        hue_i = int(hue_f)
        hue_f -= hue_i
        sat = saturation
        val = value
        grad_p = val * (1 - sat)
        grad_q = val * (1 - sat * hue_f)
        grad_t = val * (1 - sat * (1 - hue_f))

    red = ((hue_i == 0) | (hue_i >= 5)) * val
    red = red + (hue_i == 1) * grad_q
    red = red + ((hue_i == 2) | (hue_i == 3)) * grad_p
    red = red + (hue_i == 4) * grad_t

    green = ((hue_i == 0) | (hue_i >= 6)) * grad_t
    green = green + ((hue_i == 1) | (hue_i == 2)) * val
    green = green + (hue_i == 3) * grad_q
    green = green + ((hue_i == 4) | (hue_i == 5)) * grad_p

    blue = ((hue_i == 0) | (hue_i == 1) | (hue_i >= 6)) * grad_p
    blue = blue + (hue_i == 2) * grad_t
    blue = blue + ((hue_i == 3) | (hue_i == 4)) * val
    blue = blue + (hue_i == 5) * grad_q

    return (red, green, blue)
示例#9
0
    def absorb(self):
        """
        Implement the logic of absorb phase.

        Statements below will be translated into C code as well.

        Here, we sum all neigbors buffered states and apply Conway
        rule to modify cell's own state.

        """
        neighbors_alive = core.IntegerVariable()
        for i in range(len(self.buffers)):
            neighbors_alive += self.neighbors[i].buffer.state
        is_born = (8 >> neighbors_alive) & 1
        is_sustain = (12 >> neighbors_alive) & 1
        self.main.state = is_born | is_sustain & self.main.state
示例#10
0
def genome_crossover(state, num_genes, *genomes, max_genes=None,
                     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 the same number of genes.
    :param genomes:
        A list of genomes (integers) to crossover
    :param max_genes:
        Upper limit for '1' genes in the resulting genome.
    :param mutation_prob:
        Probability of a single gene's mutation.
    :param rng_name:
        Name of ``RandomProperty``.

    :returns: Single integer, a resulting genome.

    """
    max_genes = max_genes or num_genes
    gene_choose = core.IntegerVariable()
    new_genome = core.IntegerVariable()
    num_genomes = core.IntegerVariable()
    num_active = core.IntegerVariable()
    new_gene = core.IntegerVariable()
    rand_val = getattr(state, rng_name).uniform
    start_gene = core.IntegerVariable()
    start_gene *= 0
    start_gene += xmath.int(rand_val * num_genes) % len(genomes)
    for gene in range(num_genes):
        gene_choose *= 0
        num_genomes *= 0
        gene = (gene + start_gene) % num_genes
        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 *= 0
        new_gene += ((gene_choose >> winner_gene) & 1)
        num_active += new_gene
        new_gene *= num_active <= max_genes
        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
示例#11
0
 def absorb(self):
     """Absorb surrounding values by summing them."""
     new_val = core.IntegerVariable()
     for i in range(len(self.buffers)):
         new_val += self.neighbors[i].buffer.state
     self.main.state = new_val