My objective is to maintain the multi-objective optimization throughout the implementation, here among the total 8 objectives 'Area',and 'PowerDissipation' are need to be minimize and the remaining 6 objectives 'SlewRate', 'Bandwidth3dB', 'GainBWProd', 'UnityGainFreq', and 'PhaseMargin' are need to be maximize.

after computing 'maximum_values, minimum_values = update_minimum_values(pareto_data, objectives)', i am getting
maximum_values, minimum_values {'Area': -inf, 'PowerDissipation': -inf, 'SlewRate': 0.0, 'Gain': -6.2179999999999325, 'Bandwidth3dB': 0.0, 'GainBWProd': 0.0, 'UnityGainFreq': 0.0, 'PhaseMargin': 0.0} {'Area': -0.0011079699860401435, 'PowerDissipation': -5.374359999999999, 'SlewRate': inf, 'Gain': inf, 'Bandwidth3dB': inf, 'GainBWProd': inf, 'UnityGainFreq': inf, 'PhaseMargin': inf}

after 'reference_point = [maximum_values[obj] if obj in ['Area', 'PowerDissipation'] else minimum_values[obj] for obj in objectives]', i am getting
reference_point [-inf, -inf, inf, inf, inf, inf, inf, inf]

In the below code the computation 'hypervolume_values = calculate_hypervolume(pareto_data, reference_point)' is not working properly please check

def update_minimum_values(pareto_data, objectives):
    # Initialize minimum and maximum values for each objective
    minimum_values = {obj: float('inf') for obj in objectives}
    maximum_values = {obj: float('-inf') for obj in objectives}

    # Adjustments here to directly use objective types
    for front_key in pareto_data:
        front_points = pareto_data[front_key]['front_fitness']
        for i, value in enumerate(front_points):
            objective = objectives[i]

            if objective in ['Area', 'PowerDissipation']:
                minimum_values[objective] = min(minimum_values[objective], value)
            else:
                maximum_values[objective] = max(maximum_values[objective], value)

    return maximum_values, minimum_values
# Perform Pareto fronts with crowding distances and hypervolume
def pareto_sort(population, fitness_values, objectives):
    non_dominated_sets = []
    domination_counts = [0] * len(population)
    dominated_by = [[] for _ in range(len(population))]
    
    # Initial population segregation into non-dominated sets
    for i in range(len(population)):
        for j in range(len(population)):
            if i != j:
                if dominates(fitness_values[i], fitness_values[j], objectives):
                    dominated_by[j].append(i)
                elif dominates(fitness_values[j], fitness_values[i], objectives):
                    domination_counts[i] += 1
        if domination_counts[i] == 0:
            if len(non_dominated_sets) == 0:  # First front
                non_dominated_sets.append([i])
            else:  # Add to the first front if not dominated
                non_dominated_sets[0].append(i)
    
    # Iteratively finding subsequent fronts
    current_front = 0
    while current_front < len(non_dominated_sets):
        next_front = []
        for i in non_dominated_sets[current_front]:
            for j in dominated_by[i]:
                domination_counts[j] -= 1
                if domination_counts[j] == 0:
                    next_front.append(j)
        if next_front:
            non_dominated_sets.append(next_front)
        current_front += 1
    print(f"Non-dominated sets: {non_dominated_sets}")
    print(f"Domination Count: {domination_counts}")
    # Generating Pareto Data with Crowding Distances
    pareto_data = {}
    for front_index, front in enumerate(non_dominated_sets):
        print("front_index", front_index)
        print("front", front)
        crowding_distance = calculate_crowding_distance(front, fitness_values, objectives)
        print("crowding_distance", crowding_distance)
        for chromosome_index in front:
            pareto_data[chromosome_index] = {
                "front": front_index + 1,  # 1-indexed front numbers
                "front_fitness": [fitness_values[chromosome_index][obj] for obj in objectives],
                "crowding_distance": crowding_distance[chromosome_index],
                "chromosome": population[chromosome_index]
            }

    # Using update_minimum_values & calculate_hypervolume
    maximum_values, minimum_values = update_minimum_values(pareto_data, objectives)

    reference_point = [maximum_values[obj] if obj in ['Area', 'PowerDissipation'] else minimum_values[obj] for obj in objectives]
    print("reference_point", reference_point)
    hypervolume_values = calculate_hypervolume(pareto_data, reference_point)

    print(f"Non-dominated sets: {non_dominated_sets}")
    print(f"Domination Counts: {domination_counts}")
    print(f"Pareto Data: {pareto_data}")
    print(f"Hypervolume Values: {hypervolume_values}")

    return pareto_data, hypervolume_values

# Calculate Hypervolume
def hypervolume_calculation(front_fitness_values, reference_point):
    if not front_fitness_values or len(front_fitness_values[0]) != len(reference_point):
        return 0.0

    # Invert minimization objectives, treating all as “maximization”
    inverted_front = []
    for values in front_fitness_values:
        # Accounting for the direction: subtract for minimization, subtract from for maximization
        inverted_values = [reference_point[i] - values[i] if i < 2 else values[i] - reference_point[i] 
                           for i in range(len(values))]
        inverted_front.append(inverted_values)

    hypervolume = 0.0
    # Sum of volumes from each point to the reference point
    for point in inverted_front:
        hypervolume += np.prod([max(0, x) for x in point])  # Ensure positive contributions only
    
    return hypervolume

def calculate_hypervolume(pareto_data, reference_point):
    hypervolume_values = []

    for _, front_info in pareto_data.items():
        front_fitness = front_info['front_fitness']
        
        # Skip empty fronts
        if not front_fitness:
            hypervolume_values.append(0.0)
            continue
        
        # Calculate and append the hypervolume for the current front
        hypervolume = hypervolume_calculation(front_fitness, reference_point)
        hypervolume_values.append(hypervolume)

    return hypervolume_values