def _remap(self):
        """Remaps the archive.

        The boundaries are relocated to the percentage marks of the distribution
        of solutions stored in the archive.

        Also re-adds all of the solutions to the archive.

        Returns:
            tuple: The result of calling :meth:`ArchiveBase.add` on the last
            item in the buffer.
        """
        # Sort all behavior values along the axis of each bc.
        sorted_bc = self._buffer.sorted_behavior_values

        # Calculate new boundaries.
        SlidingBoundariesArchive._remap_numba_helper(sorted_bc,
                                                     self._buffer.size,
                                                     self._boundaries,
                                                     self._behavior_dim,
                                                     self.dims)

        index_columns = tuple(map(list, zip(*self._occupied_indices)))
        old_sols = self._solutions[index_columns].copy()
        old_objs = self._objective_values[index_columns].copy()
        old_behs = self._behavior_values[index_columns].copy()

        self._reset_archive()
        for sol, obj, beh in zip(old_sols, old_objs, old_behs):
            # Add solutions from old archive.
            status, value = ArchiveBase.add(self, sol, obj, beh)
        for sol, obj, beh in self._buffer:
            # Add solutions from buffer.
            status, value = ArchiveBase.add(self, sol, obj, beh)
        return status, value
    def add(self, solution, objective_value, behavior_values):
        """Attempts to insert a new solution into the archive.

        This method remaps the archive after every ``self.remap_frequency``
        solutions are added. Remapping involves changing the boundaries of the
        archive to the percentage marks of the behavior values stored in the
        buffer and re-adding all of the solutions stored in the buffer `and` the
        current archive.

        Args:
            solution (array-like): See :meth:`ArchiveBase.add`
            objective_value (float): See :meth:`ArchiveBase.add`
            behavior_values (array-like): See :meth:`ArchiveBase.add`
        Returns:
            See :meth:`ArchiveBase.add`
        """
        solution = np.asarray(solution)
        behavior_values = np.asarray(behavior_values)

        self._buffer.add(solution, objective_value, behavior_values)
        self._total_num_sol += 1

        if self._total_num_sol % self._remap_frequency == 0:
            status, value = self._remap()
            self._lower_bounds = np.array(
                [bound[0] for bound in self._boundaries])
            self._upper_bounds = np.array([
                bound[dim] for bound, dim in zip(self._boundaries, self._dims)
            ])
        else:
            status, value = ArchiveBase.add(self, solution, objective_value,
                                            behavior_values)
        return status, value
    def _remap(self):
        """Remaps the archive.

        The boundaries are relocated to the percentage marks of the distribution
        of solutions stored in the archive.

        Also re-adds all of the solutions to the archive.

        Returns:
            tuple: The result of calling :meth:`ArchiveBase.add` on the last
            item in the buffer.
        """
        # Sort all behavior values along the axis of each bc.
        sorted_bc = self._buffer.sorted_behavior_values

        # Calculate new boundaries.
        SlidingBoundariesArchive._remap_numba_helper(sorted_bc,
                                                     self._buffer.size,
                                                     self._boundaries,
                                                     self._behavior_dim,
                                                     self.dims)

        # TODO (btjanaka): Add an option that allows adding solutions from the
        # previous archive that are not in the buffer.

        # Add all solutions to the new empty archive.
        self._reset_archive()
        for solution, objective_value, behavior_value in self._buffer:
            status, value = ArchiveBase.add(self, solution, objective_value,
                                            behavior_value)
        return status, value