//  [python]
def fit(self, X: Sequence[np.ndarray], y=None):
        """Fit a pervect model to the list of persistence diagrams X

        Optionally use y for supervised dimension reduction.

        Parameters
        ----------
        X : list or tuple of arrays of shape (N, 2)
            The diagrams to fit the model to. Each diagram should be an array
            of shape (N, 2) for varying N, where each row of the array is the
            birth-death or birth-lifetime coordinates of a topological feature
            in the diagram. ``X`` should then be a list or tuple of such arrays.
        """
        random_state = check_random_state(self.random_state)
        self._validate_params()

        try:
            diagram_union = np.vstack(X)
        except:
            raise ValueError(
                "Input data is not a list or tuple of diagrams! "
                "Please provide a list of ndarrays of diagrams."
            )

        diagram_union = check_array(diagram_union)
        if diagram_union.shape[1] != 2:
            raise ValueError(
                "Input data is not a list or tuple of diagrams! "
                "Please provide a list of ndarrays of diagrams. "
                "Each diagram should be an array of points in the "
                "plane corresponding to either the birth-death "
                "or the birth-lifetime coordinates of an observed "
                "topological feature."
            )

        self.mixture_model_ = GaussianMixture(
            n_components=self.n_components, random_state=random_state
        )
        self.mixture_model_.fit(diagram_union)
        self._raw_ground_distance = pairwise_gaussian_ground_distance(
            self.mixture_model_.means_, self.mixture_model_.covariances_,
        )
        self.ground_distance_ = add_birth_death_line(
            self._raw_ground_distance,
            self.mixture_model_.means_,
            self.mixture_model_.covariances_,
            y_axis=self.y_axis,
        )

        if self.apply_umap:
            random_state = check_random_state(self.random_state)
            self.train_vectors_ = np.vstack(
                [vectorize_diagram(diagram, self.mixture_model_) for diagram in X]
            )
            if self.umap_metric == "wasserstein":
                self._distance_matrix = pairwise_distances(
                    self.train_vectors_,
                    metric=persistence_wasserstein_distance,
                    ground_distance=self.ground_distance_ ** self.p,
                )
                self._distance_matrix = np.power(self._distance_matrix, 1.0 / self.p)
                random_state = check_random_state(self.random_state)
                self.umap_ = umap.UMAP(
                    metric="precomputed",
                    n_components=self.umap_n_components,
                    random_state=random_state,
                ).fit(self._distance_matrix)
            elif self.umap_metric == "hellinger":
                try:
                    self.umap_ = umap.UMAP(
                        metric="hellinger",
                        n_components=self.umap_n_components,
                        random_state=random_state,
                    ).fit(self.train_vectors_)
                except ValueError:
                    warn("Hellinger metric not available ... falling back to cosine")
                    self.umap_ = umap.UMAP(
                        metric="cosine",
                        n_components=self.umap_n_components,
                        random_state=random_state,
                    ).fit(self.train_vectors_)
            else:
                raise ValueError(
                    'umap_metric shoud be one of "wasserstein" or ' '"hellinger".'
                )

        return self