//  [python]
def test_gmm_familiarity_scores(gaussian_count: int, number_new_samples: int,
                                cov_type: GMMCovarianceType) -> None:
    """
    Test that the scores familiarity and check that results are the same as returned by the sklearn
    GaussianMixture
    """
    # Fit familiarity
    producer, stub_data, familiarity_processor = create_familiarity_processor(
        gaussian_count=gaussian_count,
        covariance_type=cov_type
    )

    # Fit sklearn GMM and compare with DNIKit fitted GMM
    sklearn_gm = {}
    random_state_instance = np.random.RandomState(seed=1)
    for response_name, response_data in stub_data.items():
        sklearn_gm[response_name] = GaussianMixture(n_components=gaussian_count,
                                                    max_iter=200,
                                                    tol=1e-3,
                                                    covariance_type=cov_type.value,
                                                    random_state=random_state_instance)
        sklearn_gm[response_name].fit(response_data)

        def extract_covs(c: np.ndarray) -> np.ndarray:
            """Returns squared covariances regardless of fitting type."""
            if cov_type is GMMCovarianceType.FULL:
                return c
            elif cov_type is GMMCovarianceType.DIAG:
                return np.array([np.diag(ci) for ci in c])
            else:
                raise NotImplementedError(f'Unknown covariance type {cov_type}')

        # compare fitted gaussians
        distribution = familiarity_processor._distributions[response_name]
        assert isinstance(distribution, _MixtureOfMultivariateGaussianDistributions)
        assert np.allclose(
            sklearn_gm[response_name].means_,
            [np.atleast_1d(np.squeeze(g.mean)) for g in distribution.gaussians]
        )
        assert np.allclose(
            extract_covs(sklearn_gm[response_name].covariances_),
            [g.covariance for g in distribution.gaussians]
        )
        assert np.allclose(
            sklearn_gm[response_name].weights_,
            distribution.weights
        )

    # Generate new data to be evaluated and compare evaluation
    random_state = np.random.RandomState(seed=12345)
    new_data = {}
    new_data_sk_score_sample = {}
    for response_name, response_data in stub_data.items():
        # generate test samples for each layer
        new_data[response_name] = random_state.randn(number_new_samples, response_data.shape[1])

        # compute weighted log-likelihood
        new_data_sk_score_sample[response_name] = (
            sklearn_gm[response_name].score_samples(new_data[response_name])
        )

    # Evaluate familiarity of new data
    new_data_producer = StubProducer(new_data)
    familiarity_producer = pipeline(new_data_producer, familiarity_processor)

    # Compare sk and dnikit familiarity evaluation on new data
    # Note: the current implementation achieves a slightly different results when evaluating the
    # log-pdf. This seems to be a numerical precision problem. For this reason, results are
    # evaluated in terms of pdf and not log-pdf.
    for i, batch in enumerate(familiarity_producer(1)):
        for response_name in batch.fields.keys():
            assert np.isclose(
                np.exp(new_data_sk_score_sample[response_name][i]),
                np.exp(batch.metadata[familiarity_processor.meta_key][response_name][0].score),
                atol=1e-2
            )

    # Compare sk and dnikit ranking
    # Note: due to the issue of numerical stability it can happen if the seed is changed that the
    # ranking becomes slightly different. See issue #427
    for response_name in stub_data.keys():
        dnikit_sorted_scores = sorted([
            (index, batch.metadata[familiarity_processor.meta_key][response_name][index].score)
            for batch in familiarity_producer(number_new_samples)
            for index in range(batch.batch_size)
        ], reverse=True, key=lambda x: x[1])

        sk_sorted_scores = sorted([
            (index, new_data_sk_score_sample[response_name][index])
            for index in range(new_data_sk_score_sample[response_name].shape[0])
        ], reverse=True, key=lambda x: x[1])

        # Note: if the number of samples is increased, it's possible to get a pair of samples where
        # order is swapped
        # Solution: would be to achieve same result as sklearn by improving numerical precision
        assert [v[0] for v in dnikit_sorted_scores] == [v[0] for v in sk_sorted_scores]