def color(self): """Render cell's genome as hue/sat, cell's energy as value.""" if self._legacy_coloring: red, green, blue = GenomeColor.modular(self.main.rule >> 1, 360) else: red, green, blue = GenomeColor.positional(self.main.rule, self.main.rule.bit_width) is_live = (self.main.rule > 0) * (self.main.energy < 255) energy = (255 - self.main.energy) * is_live red = xmath.int(red * energy) green = xmath.int(green * energy) blue = xmath.int(blue * energy) return (red, green, blue, )
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
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
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
def _get_next(self): """Generate and return the next RNG value.""" val_int = xmath.int(DeferredExpression(self.var_name)) val = ((val_int * 58321 + 11113)) % 65535 self.__set__(self, val) container = inspect.currentframe().f_back.f_locals['obj'] self.bsca.deferred_write(container)
def color(self): """Render cell's genome as hue/sat, cell's energy as value.""" if self._legacy_coloring: red, green, blue = GenomeColor.modular(self.main.rule >> 1, 360) else: red, green, blue = GenomeColor.positional(self.main.rule, self.main.rule.bit_width) shade = xmath.min(self.main.energy, self.meta.full_treshold) shade = shade * 255 / self.meta.full_treshold red = xmath.int(red * shade) green = xmath.int(green * shade) blue = xmath.int(blue * shade) return ( red, green, blue, )
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)
def color(self): """Make some noise, now for real.""" val = xmath.int(self.main.rng.uniform * 255) return (val, val, val)