among the total objectives 'objectives = ['Area', 'PowerDissipation', 'SlewRate', 'Gain', 'Bandwidth3dB', 'GainBWProd', 'UnityGainFreq', 'PhaseMargin']', the 'Area',and 'PowerDissipation' are need to be minimum, and 'SlewRate', 'Gain', 'Bandwidth3dB', 'GainBWProd', 'UnityGainFreq',and 'PhaseMargin' are need to be maximum.
i am getting Hypervolume Values for all the individual chromosomes present in the pareto data as '0' ({0: 0, 1: 0, 2: 0, 3: 0}). please debug the error in the code and provide me the updated code with the criteria of multi-objective optimization to be synchronized in all aspects.

Fitness Extremes: {'Area': [-0.0008552177598742217, -0.0009585952219251429, -0.0012949543479610325, -0.0006185368251147396], 'PowerDissipation': [-4.97817, -0.9063679999999998, -2.26906, -0.8858769999999999], 'SlewRate': [], 'Gain': [-146.61299999999997, -193.082, -45.959, -23.281000000000063], 'Bandwidth3dB': [-2.20198, -0.7388599999999997, -0.24575999999999995, -4.489746], 'GainBWProd': [-0.19364400000000012], 'UnityGainFreq': [-0.8175899999999992], 'PhaseMargin': [-493.43999999999994, -541.06, -738.7799999999999]}

Calculated Reference Points: {'Area': -0.0005566831426032657, 'PowerDissipation': -0.7972892999999999, 'SlewRate': -0.1, 'Gain': -212.3902, 'Bandwidth3dB': -4.9387206, 'GainBWProd': -0.21300840000000013, 'UnityGainFreq': -0.8993489999999991, 'PhaseMargin': -812.6579999999999}

Transformed Data for Key 0: [0.00029853461727095607, 4.1808807, 0.1, 65.77720000000002, 2.7367406, 0.21300840000000013, 0.8993489999999991, 812.6579999999999]
Transformed Data for Key 1: [0.00040191207932187723, 0.10907869999999997, 0.1, 19.3082, 4.1998606, 0.019364400000000004, 0.08175899999999992, 319.21799999999996]
Transformed Data for Key 2: [0.0007382712053577668, 1.4717707000000002, 0.1, 166.4312, 4.6929606, 0.21300840000000013, 0.8993489999999991, 271.59799999999996]
Transformed Data for Key 3: [6.185368251147394e-05, 0.08858770000000005, 0.1, 189.10919999999993, 0.44897459999999967, 0.21300840000000013, 0.8993489999999991, 73.87800000000004]

Base Volume for Key 0: 3.497875054053763
Total Intersect Volume for Key 0: 54.81480190857676
Individual Hypervolume for Key 0: 0
Base Volume for Key 1: 0.00017966962651894214
Total Intersect Volume for Key 1: 12.629451851169332
Individual Hypervolume for Key 1: 0
Base Volume for Key 2: 4.415595573200914
Total Intersect Volume for Key 2: 47.738753914922356
Individual Hypervolume for Key 2: 0
Base Volume for Key 3: 0.0006584359468470561
Total Intersect Volume for Key 3: 15.286571441638149
Individual Hypervolume for Key 3: 0

Hypervolume Values: {0: 0, 1: 0, 2: 0, 3: 0}


def update_reference_points(pareto_data, objectives):
    # Collect all fitness values per objective
    fitness_extremes = {obj: [] for obj in objectives}
    for data in pareto_data.values():
        for i, obj in enumerate(objectives):
            # Avoid considering zero values which signify ideal performance
            if data['fitness'][i] != 0:  
                fitness_extremes[obj].append(data['fitness'][i])
    
    # Debug print to check content of fitness_extremes after collection
    print("Fitness Extremes:", fitness_extremes)
    
    # Calculate robust reference points
    reference_points = {}
    for obj in objectives:
        if obj in ['Area', 'PowerDissipation']:  # Maximizing these objectives’ extremes in minimization context
            if fitness_extremes[obj]:  # Ensure there are valid entries
                max_val = max(fitness_extremes[obj])
                reference_points[obj] = max_val + (0.1 * abs(max_val))
            else:
                reference_points[obj] = 0.1  # Default small value if no extremities found
        else:  # Minimizing these objectives’ extremes in maximization context
            if fitness_extremes[obj]:
                min_val = min(fitness_extremes[obj])
                reference_points[obj] = min_val - (0.1 * abs(min_val))
            else:
                reference_points[obj] = -0.1  # Default small negative value if no extremities found
    
    # Debug print to check calculated reference points
    print("Calculated Reference Points:", reference_points)
    
    return reference_points


# Perform Pareto fronts with crowding distances and hypervolume
def pareto_sort(population, fitness_values, objectives):
    non_dominated_sets = []
    domination_counts = [0 for _ in population]
    dominated_by = [[] for _ in population]
    
    # Compare each pair of individuals
    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
    
    # Identify non-dominated individuals (first front)
    current_set = [i for i, count in enumerate(domination_counts) if count == 0]
    non_dominated_sets.append(current_set)
    
    # Iteratively find subsequent fronts
    front_index = 0
    while front_index < len(non_dominated_sets):
        next_front = []
        for i in non_dominated_sets[front_index]:
            for j in dominated_by[i]:
                domination_counts[j] -= 1
                if domination_counts[j] == 0:
                    next_front.append(j)
        if next_front:  # Only append if not empty
            non_dominated_sets.append(next_front)
        front_index += 1
    
    print(f"Non-dominated sets: {non_dominated_sets}")
    print(f"Domination Count: {domination_counts}")
    pareto_data = {}
    # Calculate crowding distance and prepare pareto data for each front
    for front_index, front in enumerate(non_dominated_sets):
        if len(front) > 0:
            crowding_distances = calculate_crowding_distance(front, fitness_values, objectives)
            for i, chromosome_index in enumerate(front):
                pareto_data[chromosome_index] = {
                    "front": front_index + 1,
                    "chromosome": population[chromosome_index],
                    "fitness": [fitness_values[chromosome_index][obj] for obj in objectives],
                    "crowding_distance": crowding_distances[i]
                }
    print("Pareto Data:", pareto_data)
    # Calculate hypervolume and min/max reference points
    reference_points = update_reference_points(pareto_data, objectives)
    print("Calculated Reference Points:", reference_points)
    hypervolume_values = calculate_individual_hypervolumes(pareto_data, reference_points, objectives)
    print(f"Hypervolume Values: {hypervolume_values}")
    return pareto_data, hypervolume_values

def calculate_individual_hypervolumes(pareto_data, reference_points, objectives):
    individual_volumes = {}

    # Transform all fitness values ensuring reference points are correctly applied.
    transformed_data = {}
    for key, data in pareto_data.items():
        transform = []
        for i, obj in enumerate(objectives):
            fitness_value = data['fitness'][i]
            # Determine if objective is to be minimized or maximized
            objective_type = 'minimize' if obj in ['Area', 'PowerDissipation'] else 'maximize'
            # Use the reference point directly associated with objective name
            if objective_type == 'minimize':
                transformed_value = reference_points[obj] - fitness_value
            else:
                transformed_value = fitness_value - reference_points[obj]
            # Ensure non-negative values, guaranteeing non-negative hypervolume
            transform.append(max(0, transformed_value))
        
        transformed_data[key] = transform
        print(f"Transformed Data for Key {key}: {transform}")
    # Calculate the individual hypervolumes
    for key in transformed_data:
        base_volume = np.prod(transformed_data[key])
        print(f"Base Volume for Key {key}: {base_volume}")
        intersect_volumes = []
        for other_key in transformed_data:
            if other_key != key:
                intersect_data = [max(transformed_data[key][i], transformed_data[other_key][i]) for i in range(len(objectives))]
                intersect_volumes.append(np.prod(intersect_data))
        
        total_intersect_volume = sum(intersect_volumes) if intersect_volumes else 0
        print(f"Total Intersect Volume for Key {key}: {total_intersect_volume}")
        individual_volumes[key] = max(0, base_volume - total_intersect_volume)
        print(f"Individual Hypervolume for Key {key}: {individual_volumes[key]}")
    print("All Calculated Individual Hypervolumes:", individual_volumes)
    return individual_volumes

objectives = ['Area', 'PowerDissipation', 'SlewRate', 'Gain', 'Bandwidth3dB', 'GainBWProd', 'UnityGainFreq', 'PhaseMargin']
# Calculate hypervolume and reference points
reference_points = update_reference_points(pareto_data, objectives)
print("Calculated Reference Points:", reference_points)
hypervolume_values = calculate_individual_hypervolumes(pareto_data, reference_points, objectives)
print(f"Hypervolume Values: {hypervolume_values}")