class GmmTrainer extends SingleLabelDatasetTrainer<GmmModel> {

    private Optional<GmmModel> fit(Dataset<EmptyContext, GmmPartitionData> dataset) {
        return init(dataset).map(model -> {
            GmmModel currentModel = model;

            do {
                UpdateResult updateResult = updateModel(dataset, currentModel);
                currentModel = updateResult.model;

                double minCompProb = currentModel.componentsProbs().minElement().get();
                if (countOfComponents >= maxCountOfClusters || minCompProb < minClusterProbability)
                    break;

                double maxXProb = updateResult.maxProbInDataset;
                NewComponentStatisticsAggregator newMeanAdder = NewComponentStatisticsAggregator.computeNewMean(dataset,
                    maxXProb, maxLikelihoodDivergence, currentModel);

                Vector newMean = newMeanAdder.mean();
                if (newMeanAdder.rowCountForNewCluster() < minElementsForNewCluster)
                    break;

                countOfComponents += 1;
                Vector[] newMeans = new Vector[countOfComponents];
                for (int i = 0; i < currentModel.countOfComponents(); i++)
                    newMeans[i] = currentModel.distributions().get(i).mean();
                newMeans[countOfComponents - 1] = newMean;

                initialMeans = newMeans;

                Optional<GmmModel> newModelOpt = init(dataset);
                if (newModelOpt.isPresent())
                    currentModel = newModelOpt.get();
                else
                    break;
            }
            while (true);

            return filterModel(currentModel);
        });
    }

    public  GmmTrainer();
    public  GmmTrainer(int countOfComponents, int maxCountOfIterations);
    public  GmmTrainer(int countOfComponents);

}