input: Write a python function to implement a genetic algorithm for finding the minimum of a given function.
  assert isinstance(genetic_algorithm(50), float)
  assert genetic_algorithm(50) < 5
  assert len(gen_population(50)) == 50
output: import random
  import numpy as np
  
  def genetic_algorithm(population_size):
      def objective_function(x):
          return x ** 2
  
      def gen_population(size):
          return [random.uniform(-10, 10) for _ in range(size)]
  
      def select_parents(population):
          return random.choices(population, k=2)
  
      def crossover(parent1, parent2):
          alpha = random.random()
          return alpha * parent1 + (1 - alpha) * parent2
  
      def mutate(child):
          if random.random() < 0.1:
              child += random.uniform(-1, 1)
          return child
  
      population = gen_population(population_size)
      for _ in range(100):  # Run for 100 generations
          population = sorted(population, key=objective_function)
          new_population = population[:2]  # Elitism: keep the top 2
          while len(new_population) < population_size:
              parent1, parent2 = select_parents(population)
              child = crossover(parent1, parent2)
              child = mutate(child)
              new_population.append(child)
          population = new_population
  
      best_solution = min(population, key=objective_function)
      return best_solution
  
  def gen_population(size):
      return [random.uniform(-10, 10) for _ in range(size)]