Calculates and updates the fitness and best_fitness of a particle.

    Fitness is calculated using the 'problem.fitness' function.

    Args:
        problem: The optimization problem encapsulating the fitness function
            and optimization type.
        particle: cipy.algorithms.pso.Particle: Particle to update the fitness
            for.

    Returns:
        cipy.algorithms.pso.Particle: A new particle with the updated fitness.

def update_fitness(objective_function, particle):
    """ Calculates and updates the fitness and best_fitness of a particle.

    Fitness is calculated using the 'problem.fitness' function.

    Args:
        problem: The optimization problem encapsulating the fitness function
            and optimization type.
        particle: cipy.algorithms.pso.Particle: Particle to update the fitness
            for.

    Returns:
        cipy.algorithms.pso.Particle: A new particle with the updated fitness.

    """
    fitness = objective_function(particle.position)
    best_fitness = particle.best_fitness
    cmp = comparator(fitness)
    if best_fitness is None or cmp(fitness, best_fitness):
        best_position = particle.position
        return particle._replace(fitness=fitness,
                                 best_fitness=fitness,
                                 best_position=best_position)
    else:
        return particle._replace(fitness=fitness)