def recursive_hypervolume()

in nevergrad/optimization/multiobjective/hypervolume.py [0:0]


    def recursive_hypervolume(self, dimension: int) -> float:
        """Recursive hypervolume computation. The algorithm is provided by Algorithm 3.
        of the original paper."""
        if self.multilist.chain_length(dimension - 1) == 0:
            return 0
        assert self.multilist is not None
        if dimension == 0:
            return -float(self.multilist.sentinel.next[0].coordinates[0])

        if dimension == 1:
            return self.plane_hypervolume()

        # Line 4
        for node in self.multilist.reverse_iterate(dimension):
            assert node is not None
            if node.dominated_flag < dimension:
                node.dominated_flag = 0
        # Line 5
        hypervolume = 0.0
        # Line 6
        current_node = self.multilist.sentinel.prev[dimension]
        # Lines 7 to 12
        for node in self.multilist.reverse_iterate(dimension, start=current_node):
            assert node is not None
            current_node = node
            if self.multilist.chain_length(dimension - 1) > 1 and (
                node.coordinates[dimension] > self.reference_bounds[dimension]
                or node.prev[dimension].coordinates[dimension] >= self.reference_bounds[dimension]
            ):
                # Line 9
                self.reference_bounds = self.multilist.update_coordinate_bounds(
                    self.reference_bounds, node, dimension
                )  # type: ignore
                # Line 10
                self.multilist.pop(node, dimension)
                # Line 11
                # front_size -= 1
            else:
                break

        # Line 13
        if self.multilist.chain_length(dimension - 1) > 1:
            # Line 14
            hypervolume = current_node.prev[dimension].volume[dimension]
            hypervolume += current_node.prev[dimension].area[dimension] * (
                current_node.coordinates[dimension] - current_node.prev[dimension].coordinates[dimension]
            )
        else:
            current_node.configure_area(dimension)

        # Line 15
        current_node.volume[dimension] = hypervolume
        # Line 16
        self.skip_dominated_points(current_node, dimension)

        # Line 17
        for node in self.multilist.iterate(dimension, start=current_node.next[dimension]):
            assert node is not None
            # Line 18
            hypervolume += node.prev[dimension].area[dimension] * (
                node.coordinates[dimension] - node.prev[dimension].coordinates[dimension]
            )
            # Line 19
            self.reference_bounds[dimension] = node.coordinates[dimension]
            # Line 20
            self.reference_bounds = self.multilist.update_coordinate_bounds(
                self.reference_bounds, node, dimension
            )  # type: ignore
            # Line 21
            self.multilist.reinsert(node, dimension)
            # Line 22
            # front_size += 1
            # Line 25
            node.volume[dimension] = hypervolume
            # Line 26
            self.skip_dominated_points(node, dimension)

        # Line 27
        last_node = self.multilist.sentinel.prev[dimension]
        hypervolume -= last_node.area[dimension] * last_node.coordinates[dimension]
        return hypervolume