IN this below code, my actual objective is to choose the pareto optimal solutions for the multi objective technique, generally all the implementation have performed, the fitness values of each perfromance metrics values(normalized difference of obtained and desired performance metrics) are aggregated into single fitness values and find their optimization goal make the multi objective optimization into single objective because of aggregation. but i fing the individual fitness values and calculating the pareto front. in need you  to review the below code, whether the following implementation are making the same mistake as aggregating the muliobjective into single objective in any part. please check.

def weighted_sum_aggregation(chromosome_fitness_values, weights):
    return [sum(w * val for w, val in zip(weights, obj_values)) for obj_values in zip(*chromosome_fitness_values)]

# Perform Pareto fronts with crowding distances and hypervolume
def pareto_sort(population, fitness_values, objectives):
    non_dominated_sets = []
    domination_count = [0] * len(population)

    for i in range(len(population)):
        added_to_existing_set = False
        for front in non_dominated_sets:
            if any(dominates(fitness_values[i], fitness_values[j], objectives) for j in front):
                front.append(i)
                added_to_existing_set = True
                break

        if not added_to_existing_set:
            non_dominated_sets.append([i])

    current_level = 0
    while non_dominated_sets:
        next_level = []
        for chromosome in non_dominated_sets[current_level]:
            for j in range(len(population)):
                if chromosome != j and dominates(fitness_values[chromosome], fitness_values[j], objectives):
                    domination_count[j] -= 1
                    if domination_count[j] == 0:
                        next_level.append(j)

        if next_level:
            non_dominated_sets.append(next_level)
            current_level += 1
        else:
            break

    print(f"Non-dominated sets: {non_dominated_sets}")
    print(f"Domination Count: {domination_count}")

    pareto_data = {}    
    for front in non_dominated_sets:
        if len(front) > 1:  # Apply aggregation only if there is more than one chromosome in the front
            # Extract fitness values for each chromosome in the front
            chromosome_fitness_values = [[value for value in fitness_values[front_key].values()] for front_key in front]

            # Assign equal weights for simplicity (you can adjust weights based on importance)
            weights = [1.0] * len(chromosome_fitness_values[0])

            # Use the weighted sum aggregation method
            aggregated_fitness = weighted_sum_aggregation(chromosome_fitness_values, weights)

            crowding_distance = calculate_crowding_distance(front, fitness_values, population, objectives)
            
            pareto_data[front[0]] = {
                "front": front,
                "front_fitness": aggregated_fitness,
                "crowding_distance": crowding_distance,
                "chromosome": population[front[0]]
            }
        else:
            # If only one chromosome in the front, use its original fitness values
            crowding_distance = calculate_crowding_distance(front, fitness_values, population, objectives)
            
            pareto_data[front[0]] = {
                "front": front,
                "front_fitness": list(fitness_values[front[0]].values()),
                "crowding_distance": crowding_distance,
                "chromosome": population[front[0]]
            }
            
    print(f"Pareto Data: {pareto_data}")

    # Update minimum values based on the front points in pareto_data
    maximum_values, minimum_values = update_minimum_values(pareto_data, objectives)

    # Set the reference point based on the criteria
    reference_point = [maximum_values[objective] if i < 2 else minimum_values[objective] for i, objective in enumerate(objectives)]

    # Calculate Hypervolume
    hypervolume_values = calculate_hypervolume(pareto_data, reference_point, fitness_values)
    print(f"hypervolume_values: {hypervolume_values}")

    return pareto_data, hypervolume_values

# Determine dominance relationship
def dominates(fitness_values_a, fitness_values_b, objectives):
    # Check if fitness_values_a dominates fitness_values_b
    dominates_a = False
    dominates_b = False   

    for objective in objectives:
        value_a = fitness_values_a[objective]
        value_b = fitness_values_b[objective]
        
        if objective in ['Area', 'PowerDissipation']:
            # For objectives to be minimized, lower values are better
            if value_a < value_b:
                dominates_a = True
            elif value_a > value_b:
                dominates_b = True
        else:
            # For objectives to be maximized, higher values are better
            if value_a > value_b:
                dominates_a = True
            elif value_a < value_b:
                dominates_b = True    

    return dominates_a and not dominates_b