示例#1
0
def initialize_population(pop_size, s_xspan, s_yspan, seed_density):
    """
  Randomly initialize the population of seeds.
  """
    #
    # Initialize the population: a list of seeds.
    #
    # Here a seed is an initial Game of Life pattern (it is
    # not a random number seed).
    #
    population = []
    #
    for i in range(pop_size):
        # Make an empty seed (all zeros).
        seed = mclass.Seed(s_xspan, s_yspan, pop_size)
        # Randomly set some cells to state 1 (red).
        seed.randomize(seed_density)
        # Set the count of living cells.
        seed.num_living = seed.count_ones()
        # Set the position of the new seed in the population array.
        seed.address = i
        # Add the seed to the population.
        population.append(seed)
        #
    return population
示例#2
0
def load_designed_seed(g, seed_path):
    """
  Given the path to a human-designed Game of Life pattern, load the
  file and convert it to a seed.
  """
    #
    # Golly has two kinds of cell lists, one that contains an even number
    # of members and one that contains an odd number of members. The
    # former is intended for two states (0 and 1) and the latter is intended
    # for more than two states. Here we are only interested in patterns designed
    # for the Game of Life, which only has two states.
    #
    cell_list = g.load(seed_path)
    #
    # Make sure that cell_list is the type of list that contains an even
    # number of members. Make sure cell_list is not unreasonably small.
    #
    assert len(cell_list) % 2 == 0
    assert len(cell_list) > 10
    #
    # Convert cell_list to a list of (x, y) pairs.
    #
    pair_list = []
    min_x = cell_list[0]
    max_x = cell_list[0]
    min_y = cell_list[1]
    max_y = cell_list[1]
    #
    for i in range(0, len(cell_list), 2):
        pair = (cell_list[i], cell_list[i + 1])
        pair_list.append(pair)
        (x, y) = pair
        if (x < min_x):
            min_x = x
        if (x > max_x):
            max_x = x
        if (y < min_y):
            min_y = y
        if (y > max_y):
            max_y = y
    #
    # Convert pair_list to a seed. Start with a seed full of
    # zeros and set the cells given in pair_list to ones.
    #
    assert min_x == 0
    assert min_y == 0
    assert max_x > 0
    assert max_y > 0
    #
    s_xspan = max_x + 1
    s_yspan = max_y + 1
    #
    seed = mclass.Seed(s_xspan, s_yspan, mparam.pop_size)
    #
    for pair in pair_list:
        (x, y) = pair
        seed.cells[x][y] = 1
    #
    return seed
示例#3
0
def mate(seed0, seed1):
    """
  Apply crossover to seed0 and seed1. We only have one crossover point,
  because multiple crossover points would be more disruptive to the
  structure of the seeds.
  """
    # This function is designed with the assumption that the seeds are
    # the same size.
    assert seed0.xspan == seed1.xspan
    assert seed0.yspan == seed1.yspan
    # Note the spans of seed0 and seed1.
    xspan = seed0.xspan
    yspan = seed0.yspan
    # Randomly swap the seeds. Because s0 is always the top part of
    # a split that cuts across the Y axis and the left part of a split
    # that cuts across the X axis, we need to swap the seeds in order
    # to add some variety.
    if (rand.uniform(0, 1) < 0.5):
        s0 = seed0
        s1 = seed1
    else:
        s0 = seed1
        s1 = seed0
    # Initialize the child to zero.
    child_seed = mclass.Seed(xspan, yspan, mparam.pop_size)
    # Randomly choose whether to split on the X axis or
    # the Y axis.
    if (rand.uniform(0, 1) < 0.5):
        # Choose the Y axis split point. There will always be
        # at least one row on either side of the split point.
        assert yspan > 1
        y_split_point = rand.randrange(yspan - 1)
        for x in range(xspan):
            for y in range(yspan):
                if (y <= y_split_point):
                    child_seed.cells[x][y] = s0.cells[x][y]
                else:
                    child_seed.cells[x][y] = s1.cells[x][y]
    else:
        # Choose the X axis split point. There will always be
        # at least one column on either side of the split point.
        assert xspan > 1
        x_split_point = rand.randrange(xspan - 1)
        for x in range(xspan):
            for y in range(yspan):
                if (x <= x_split_point):
                    child_seed.cells[x][y] = s0.cells[x][y]
                else:
                    child_seed.cells[x][y] = s1.cells[x][y]
    # Return the resulting child.
    return child_seed
示例#4
0
def fusion(candidate_seed, pop, n, max_seed_area):
    """
  Fuse two seeds together. Randomly rotate the seeds before
  joining them. Let's put one seed on the left and the other 
  seed on the right. Insert one empty column between the two 
  seeds, as a kind of buffer, so that the two seeds do not 
  immediately interact. This empty column also helps fission
  later on, to split joined seeds at the same point where they
  were initially joined.
  """
    # The most fit member of the tournament.
    s0 = candidate_seed
    # Run another tournament to select a second seed. The second
    # seed might be identical to the first seed. That's OK.
    tournament_size = mparam.tournament_size
    tournament_sample = random_sample(pop, tournament_size)
    s1 = find_best_seed(tournament_sample)
    # Randomly rotate the seeds. These rotations (s2 and s3) are copies.
    # The originals (s0 and s1) are not affected by the rotations.
    s2 = s0.random_rotate()
    s3 = s1.random_rotate()
    # Get dimensions for the new fusion seed.
    pop_size = mparam.pop_size
    xspan = s2.xspan + s3.xspan + 1  # left width + right width + empty gap
    yspan = max(s2.yspan, s3.yspan)  # the larger of the two heights
    # Make sure the area of the new seed is not greater than the maximum.
    # If it is too big, then default to sexual reproduction.
    if ((xspan * yspan) > max_seed_area):
        return sexual(candidate_seed, pop, n, max_seed_area)
    # Copy s2 into the left side of s4.
    s4 = mclass.Seed(xspan, yspan, pop_size)  # cells initialized to zero
    for x in range(s2.xspan):
        for y in range(s2.yspan):
            s4.cells[x][y] = s2.cells[x][y]
    # Copy s3 into the right side of s4.
    for x in range(s3.xspan):
        for y in range(s3.yspan):
            s4.cells[x + s2.xspan + 1][y] = s3.cells[x][y]
    # Find the least fit old seed in the population. It's not a problem
    # if there are ties.
    s5 = find_worst_seed(pop)
    # Now we have:
    #
    # s0 = seed 0
    # s1 = seed 1
    # s2 = rotated seed 0
    # s3 = rotated seed 1
    # s4 = the fusion of s2 and s3
    # s5 = the least fit old seed, which will be replaced by s4
    #
    # NOTE: we're not applying mutation here, because this is not a form
    # of reproduction. It's a merger of two seeds.
    #
    # Replace the least fit old seed in the population (s5) with the
    # new fusion seed (s4).
    i = s5.address  # find the position of the old seed (s5)
    s4.address = i  # copy the old position of the old seed into s4, the new fusion seed
    pop[i] = s4  # replace s5 (old seed) in population (pop) with s4 (new fusion seed)
    # Build a history for the new seed, by matching it against all seeds
    # in the population.
    width_factor = mparam.width_factor
    height_factor = mparam.height_factor
    time_factor = mparam.time_factor
    num_trials = mparam.num_trials
    for j in range(pop_size):
        update_history(g, pop, i, j, width_factor, height_factor, \
          time_factor, num_trials)
        update_similarity(pop, i, j)
    # Report on the new history of the new seed.
    message = "Run: {}".format(n) + \
      "  Seed 0 fitness (s0): {:.3f}".format(s0.fitness()) + \
      "  Seed 1 fitness (s1): {:.3f}".format(s1.fitness()) + \
      "  Fusion fitness (s4): {:.3f}".format(s4.fitness()) + \
      "  Replaced seed fitness (s5): {:.3f}\n".format(s5.fitness())
    # Return with the updated population and a message.
    return [pop, message]