@File : _metrics.py @Time : 2025/02/05 14:40:24 @Author : Alejandro Marrero @Version : 1.0 @Contact : amarrerd@ull.edu.es @License : (C)Copyright 2025, Alejandro Marrero @Desc : None

Statistics

Source code in digneapy/_core/_metrics.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
class Statistics:
    def __init__(self):
        self._stats_s = tools.Statistics(key=attrgetter("s"))
        self._stats_p = tools.Statistics(key=attrgetter("p"))
        self._stats_f = tools.Statistics(key=attrgetter("fitness"))

        self._stats = tools.MultiStatistics(
            s=self._stats_s, p=self._stats_p, fitness=self._stats_f
        )
        self._stats.register("mean", np.mean)
        self._stats.register("std", np.std)
        self._stats.register("min", np.min)
        self._stats.register("max", np.max)
        self._stats.register("qd_score", np.sum)

    def __call__(
        self, population: Sequence[Instance], as_series: bool = False
    ) -> dict | pd.Series:
        """Calculates the statistics of the population.
        Args:
            population (Sequence[Instance]): List of instances to calculate the statistics.
        Returns:
            dict: Dictionary with the statistics of the population.
        """
        if len(population) == 0:
            raise ValueError(
                "Error: Trying to calculate the metrics with an empty population"
            )
        if not all(isinstance(ind, Instance) for ind in population):
            raise TypeError("Error: Population must be a sequence of Instance objects")

        record = self._stats.compile(population)
        if as_series:
            _flatten_record = {}
            for key, value in record.items():
                if isinstance(value, dict):  # Flatten nested dicts
                    for sub_key, sub_value in value.items():
                        _flatten_record[f"{key}_{sub_key}"] = sub_value
                else:
                    _flatten_record[key] = value
            return pd.Series(_flatten_record)
        else:
            return record

__call__(population, as_series=False)

Calculates the statistics of the population. Args: population (Sequence[Instance]): List of instances to calculate the statistics. Returns: dict: Dictionary with the statistics of the population.

Source code in digneapy/_core/_metrics.py
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def __call__(
    self, population: Sequence[Instance], as_series: bool = False
) -> dict | pd.Series:
    """Calculates the statistics of the population.
    Args:
        population (Sequence[Instance]): List of instances to calculate the statistics.
    Returns:
        dict: Dictionary with the statistics of the population.
    """
    if len(population) == 0:
        raise ValueError(
            "Error: Trying to calculate the metrics with an empty population"
        )
    if not all(isinstance(ind, Instance) for ind in population):
        raise TypeError("Error: Population must be a sequence of Instance objects")

    record = self._stats.compile(population)
    if as_series:
        _flatten_record = {}
        for key, value in record.items():
            if isinstance(value, dict):  # Flatten nested dicts
                for sub_key, sub_value in value.items():
                    _flatten_record[f"{key}_{sub_key}"] = sub_value
            else:
                _flatten_record[key] = value
        return pd.Series(_flatten_record)
    else:
        return record

qd_score(instances_fitness)

Calculates the Quality Diversity score of a set of instances fitness.

Parameters:
  • instances (Sequence[float]) –

    List with the fitness of several instances to calculate the QD score.

Returns:
  • float( float64 ) –

    Sum of the fitness of all instances.

Source code in digneapy/_core/_metrics.py
23
24
25
26
27
28
29
30
31
32
def qd_score(instances_fitness: Sequence[float]) -> np.float64:
    """Calculates the Quality Diversity score of a set of instances fitness.

    Args:
        instances (Sequence[float]): List with the fitness of several instances to calculate the QD score.

    Returns:
        float: Sum of the fitness of all instances.
    """
    return np.sum(instances_fitness)

qd_score_auc(qd_scores, batch_size)

Calculates the Quantifying Efficiency in Quality Diversity Optimization In quality diversity (QD) optimization, the QD score is a holistic metric which sums the objective values of all cells in the archive. Since the QD score only measures the performance of a QD algorithm at a single point in time, it fails to reflect algorithm efficiency. Two algorithms may have the same QD score even though one algorithm achieved that score with fewer evaluations. We propose a metric called “QD score AUC” which quantifies this efficiency.

Parameters:
  • qd_scores (Sequence[float]) –

    Sequence of QD scores.

  • batch_size (int) –

    Number of instances evaluated in each generation.

Returns:
  • float64

    np.float64: QD score AUC metric.

Source code in digneapy/_core/_metrics.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def qd_score_auc(qd_scores: Sequence[float], batch_size: int) -> np.float64:
    """Calculates the Quantifying Efficiency in Quality Diversity Optimization
    In quality diversity (QD) optimization, the QD score is a holistic
    metric which sums the objective values of all cells in the archive.
    Since the QD score only measures the performance of a QD algorithm at a single point in time, it fails to reflect algorithm efficiency.
    Two algorithms may have the same QD score even though one
    algorithm achieved that score with fewer evaluations. We propose
    a metric called “QD score AUC” which quantifies this efficiency.

    Args:
        qd_scores (Sequence[float]): Sequence of QD scores.
        batch_size (int): Number of instances evaluated in each generation.

    Returns:
        np.float64: QD score AUC metric.
    """
    return np.sum(qd_scores) * batch_size