def __init__(self, max_dist, pop_size, reproducing_frac):
        self.algs = []
        self.all_sols = []  # all solutions, currently unused
        self.gen_best = []  # best in the generation
        self.done_iterations = 0
        self.dist_m = DIST_M
        self.df = DF

        self.num_bikes = NUM_BIKES
        self.max_dist = max_dist
        self.pop_size = pop_size
        self.num_reproducing = int(pop_size * reproducing_frac)

        while len(self.algs
                  ) < self.pop_size:  #Initializing the population of GAs
            new_alg = GA.Algorithm(parents=False, i=0)

            if new_alg.get_distance(
                    self.dist_m) <= self.max_dist:  # feasible solution
                self.algs.append(new_alg)
    def next_generation(self, i):
        pot_par = self.algs[:]
        self.infeasible = 0  # count infeasible solutions over simulation

        num_par = len(pot_par)
        repr_prob = sorted(list(range(0, num_par)), reverse=True)
        repr_prob_sum = sum(repr_prob)
        repr_prob = [r / repr_prob_sum for r in repr_prob]

        while len(self.algs) < self.pop_size:
            first_par = np.random.choice(pot_par, p=repr_prob)
            second_par = np.random.choice(pot_par, p=repr_prob)

            while first_par == second_par:
                second_par = np.random.choice(pot_par, p=repr_prob)

            new_alg = GA.Algorithm(parents=[first_par, second_par], i=i)

            if new_alg.get_distance(
                    self.dist_m) <= self.max_dist:  # feasible solution
                self.algs.append(new_alg)
            else:
                self.infeasible += 1