You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by za...@apache.org on 2019/07/25 08:05:20 UTC

[ignite] branch master updated: [ML] Hyper-parameter tuning via Genetic Algorithm (#6713)

This is an automated email from the ASF dual-hosted git repository.

zaleslaw pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new 63fbcbf  [ML] Hyper-parameter tuning via Genetic Algorithm (#6713)
63fbcbf is described below

commit 63fbcbf849640edf140047a5111a58f480c95294
Author: Alexey Zinoviev <za...@gmail.com>
AuthorDate: Thu Jul 25 13:05:03 2019 +0500

    [ML] Hyper-parameter tuning via Genetic Algorithm (#6713)
---
 .../ml/TrainingWithBinaryObjectExample.java        |   2 +
 .../clustering/CustomersClusterizationExample.java |   6 +-
 .../ml/clustering/GmmClusterizationExample.java    |   5 +-
 .../ml/clustering/KMeansClusterizationExample.java |   6 +-
 .../dataset/AlgorithmSpecificDatasetExample.java   |  35 +-
 .../ml/dataset/CacheBasedDatasetExample.java       |   3 +-
 .../IgniteModelDistributedInferenceExample.java    |  11 +-
 .../examples/ml/inference/ModelStorageExample.java |   2 +
 .../TensorFlowDistributedInferenceExample.java     |   2 +
 .../inference/TensorFlowLocalInferenceExample.java |   1 +
 .../TensorFlowThreadedInferenceExample.java        |   1 +
 .../examples/ml/knn/ANNClassificationExample.java  |   2 +
 .../examples/ml/knn/IrisClassificationExample.java |   6 +-
 .../examples/ml/knn/KNNClassificationExample.java  |  13 +-
 .../examples/ml/knn/KNNRegressionExample.java      |   6 +-
 .../multiclass/OneVsRestClassificationExample.java |   9 +-
 .../DiscreteNaiveBayesTrainerExample.java          |  10 +-
 .../GaussianNaiveBayesTrainerExample.java          |   6 +-
 .../ignite/examples/ml/nn/MLPTrainerExample.java   |   2 +
 .../ml/preprocessing/BinarizationExample.java      |   2 +
 .../examples/ml/preprocessing/ImputingExample.java |   2 +
 .../ml/preprocessing/MaxAbsScalerExample.java      |   4 +-
 .../ml/preprocessing/MinMaxScalerExample.java      |   4 +-
 .../ml/preprocessing/NormalizationExample.java     |   2 +
 .../ml/preprocessing/StandardScalerExample.java    |   4 +-
 .../linear/BostonHousePricesPredictionExample.java |   9 +-
 .../linear/LinearRegressionLSQRTrainerExample.java |  14 +-
 ...gressionLSQRTrainerWithMinMaxScalerExample.java |   9 +-
 .../linear/LinearRegressionSGDTrainerExample.java  |   6 +-
 .../BaggedLogisticRegressionSGDTrainerExample.java |  26 +-
 .../LogisticRegressionSGDTrainerExample.java       |   9 +-
 .../ml/selection/cv/CrossValidationExample.java    |  31 +-
 .../ml/selection/scoring/EvaluatorExample.java     |   6 +-
 .../selection/scoring/MultipleMetricsExample.java  |   6 +-
 .../selection/scoring/RegressionMetricExample.java |   6 +-
 .../split/TrainTestDatasetSplitterExample.java     |   9 +-
 ...eeClassificationTrainerSQLInferenceExample.java |   5 +-
 ...onTreeClassificationTrainerSQLTableExample.java |   5 +-
 .../ml/svm/SVMBinaryClassificationExample.java     |   6 +-
 .../DecisionTreeClassificationTrainerExample.java  |   5 +-
 .../tree/DecisionTreeRegressionTrainerExample.java |   2 +
 .../examples/ml/tree/FraudDetectionExample.java    |   9 +-
 .../GDBOnTreesClassificationTrainerExample.java    |   2 +
 .../GDBOnTreesRegressionTrainerExample.java        |   2 +
 .../RandomForestClassificationExample.java         |  18 +-
 .../RandomForestRegressionExample.java             |  15 +-
 .../ml/tutorial/Step_1_Read_and_Learn.java         |   5 +-
 .../examples/ml/tutorial/Step_2_Imputing.java      |   5 +-
 .../examples/ml/tutorial/Step_3_Categorial.java    |   7 +-
 .../Step_3_Categorial_with_One_Hot_Encoder.java    |   7 +-
 .../examples/ml/tutorial/Step_4_Add_age_fare.java  |   7 +-
 .../examples/ml/tutorial/Step_5_Scaling.java       |   7 +-
 .../ml/tutorial/Step_5_Scaling_with_Pipeline.java  |   5 +-
 .../ignite/examples/ml/tutorial/Step_6_KNN.java    |   5 +-
 .../ml/tutorial/Step_7_Split_train_test.java       |   6 +-
 .../ignite/examples/ml/tutorial/Step_8_CV.java     |  26 +-
 .../ml/tutorial/Step_8_CV_with_Param_Grid.java     |  30 +-
 .../Step_8_CV_with_Param_Grid_and_metrics.java     |  31 +-
 ...V_with_Param_Grid_and_metrics_and_pipeline.java |  30 +-
 .../ml/tutorial/Step_9_Scaling_With_Stacking.java  |  21 +-
 .../ml/tutorial/TutorialStepByStepExample.java     |  12 +
 .../Step_10_RandomSearch.java}                     |  56 ++-
 .../Step_11_Parallel_BrutForce_Search.java}        |  60 ++-
 .../Step_12_Parallel_Random_Search.java}           |  64 ++-
 .../Step_13_Genetic_Programming_Search.java}       |  52 ++-
 ...ep_14_Parallel_Genetic_Programming_Search.java} |  58 ++-
 .../ignite/examples/ml/util/DatasetHelper.java     |   2 +
 .../ParametricVectorGeneratorExample.java          |   1 +
 .../util/generators/StandardGeneratorsExample.java |   1 +
 .../generators/VectorGeneratorFamilyExample.java   |   1 +
 .../VectorGeneratorPrimitivesExample.java          |   1 +
 .../ml/xgboost/XGBoostModelParserExample.java      |   2 +
 .../parallelism/DefaultParallelismStrategy.java    |   6 +
 .../parallelism/NoParallelismStrategy.java         |   5 +
 .../parallelism/ParallelismStrategy.java           |  12 +-
 .../normalization/NormalizationTrainer.java        |   4 +-
 .../logistic/LogisticRegressionSGDTrainer.java     |  12 +-
 .../ml/selection/cv/AbstractCrossValidation.java   | 476 +++++++++++++++++++++
 .../ignite/ml/selection/cv/CrossValidation.java    | 408 ++----------------
 .../ml/selection/cv/CrossValidationResult.java     |  31 +-
 .../ml/selection/cv/DebugCrossValidation.java      | 116 +++++
 .../selection/paramgrid/BruteForceStrategy.java}   |  19 +-
 .../paramgrid/EvolutionOptimizationStrategy.java   | 142 ++++++
 .../paramgrid/HyperParameterTuningStrategy.java}   |  17 +-
 .../ignite/ml/selection/paramgrid/ParamGrid.java   |  48 ++-
 .../selection/paramgrid/ParameterSetGenerator.java |   6 +-
 .../ml/selection/paramgrid/RandomStrategy.java     |  84 ++++
 .../scoring/cursor/CacheBasedLabelPairCursor.java  |   4 +-
 .../scoring/cursor/LocalLabelPairCursor.java       |   4 +-
 .../ml/selection/scoring/metric/MetricValues.java  |   6 +-
 .../BinaryClassificationMetrics.java               |   4 +-
 .../metric/regression/RegressionMetrics.java       |  10 +-
 .../ml/tree/DecisionTreeClassificationTrainer.java |  18 +
 .../apache/ignite/ml/util/genetic/Chromosome.java  | 110 +++++
 .../ignite/ml/util/genetic/CrossoverStrategy.java} |  26 +-
 .../ignite/ml/util/genetic/GeneticAlgorithm.java   | 451 +++++++++++++++++++
 .../apache/ignite/ml/util/genetic/Population.java  | 159 +++++++
 .../ignite/ml/util/genetic/SelectionStrategy.java} |  23 +-
 .../ignite/ml/util/genetic/package-info.java}      |  14 +-
 .../org/apache/ignite/ml/common/TrainerTest.java   |   7 +-
 .../preprocessing/encoding/EncoderTrainerTest.java |  16 +-
 .../ml/selection/cv/CrossValidationTest.java       | 303 ++++++++++---
 .../org/apache/ignite/ml/util/UtilTestSuite.java   |   6 +-
 .../ml/util/genetic/GeneticAlgorithmTest.java      | 100 +++++
 .../ignite/ml/util/genetic/PopulationTest.java     | 126 ++++++
 105 files changed, 2747 insertions(+), 874 deletions(-)

diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/TrainingWithBinaryObjectExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/TrainingWithBinaryObjectExample.java
index 59d96c5..9eec9d1 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/TrainingWithBinaryObjectExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/TrainingWithBinaryObjectExample.java
@@ -60,6 +60,8 @@ public class TrainingWithBinaryObjectExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/clustering/CustomersClusterizationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/clustering/CustomersClusterizationExample.java
index 2295ea2..95e2bb4 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/clustering/CustomersClusterizationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/clustering/CustomersClusterizationExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.clustering;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -52,7 +52,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class CustomersClusterizationExample {
     /** Runs example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             System.out.println(">>> Ignite grid started.");
 
@@ -88,6 +88,8 @@ public class CustomersClusterizationExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/clustering/GmmClusterizationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/clustering/GmmClusterizationExample.java
index 1769c36..4c80c70 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/clustering/GmmClusterizationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/clustering/GmmClusterizationExample.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.examples.ml.clustering;
 
+import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -35,8 +36,6 @@ import org.apache.ignite.ml.util.generators.primitives.scalar.GaussRandomProduce
 import org.apache.ignite.ml.util.generators.primitives.scalar.RandomProducer;
 import org.apache.ignite.ml.util.generators.primitives.vector.VectorGeneratorsFamily;
 
-import java.util.concurrent.atomic.AtomicInteger;
-
 /**
  * Example of using GMM clusterization algorithm. Gaussian Mixture Algorithm (GMM, see {@link GmmModel}, {@link
  * GmmTrainer}) can be used for input dataset data distribution representation as mixture of multivariance gaussians.
@@ -110,6 +109,8 @@ public class GmmClusterizationExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/clustering/KMeansClusterizationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/clustering/KMeansClusterizationExample.java
index 3784aa3..edbc617 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/clustering/KMeansClusterizationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/clustering/KMeansClusterizationExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.clustering;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import javax.cache.Cache;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -49,7 +49,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class KMeansClusterizationExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> KMeans clustering algorithm over cached dataset usage example started.");
         // Start ignite grid.
@@ -96,6 +96,8 @@ public class KMeansClusterizationExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/dataset/AlgorithmSpecificDatasetExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/dataset/AlgorithmSpecificDatasetExample.java
index 09a09a7..cff63ce 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/dataset/AlgorithmSpecificDatasetExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/dataset/AlgorithmSpecificDatasetExample.java
@@ -32,6 +32,7 @@ import org.apache.ignite.ml.dataset.feature.extractor.impl.DummyVectorizer;
 import org.apache.ignite.ml.dataset.primitive.DatasetWrapper;
 import org.apache.ignite.ml.dataset.primitive.builder.data.SimpleLabeledDatasetDataBuilder;
 import org.apache.ignite.ml.dataset.primitive.data.SimpleLabeledDatasetData;
+import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.math.primitives.vector.impl.DenseVector;
@@ -77,6 +78,7 @@ public class AlgorithmSpecificDatasetExample {
 
                 Vectorizer<Integer, Vector, Integer, Double> vectorizer = new DummyVectorizer<Integer>(1);
 
+
                 IgniteFunction<LabeledVector<Double>, LabeledVector<double[]>> func = lv -> new LabeledVector<>(lv.features(), new double[]{lv.label()});
 
                 //NOTE: This class is part of Developer API and all lambdas should be loaded on server manually.
@@ -86,24 +88,24 @@ public class AlgorithmSpecificDatasetExample {
                 SimpleLabeledDatasetDataBuilder<Integer, Vector, AlgorithmSpecificPartitionContext> builder =
                     new SimpleLabeledDatasetDataBuilder<>(preprocessor);
 
-                try (AlgorithmSpecificDataset dataset = DatasetFactory.create(
-                    ignite,
-                    persons,
-                    (env, upstream, upstreamSize) -> new AlgorithmSpecificPartitionContext(),
-                    builder.andThen((data, ctx) -> {
-                        double[] features = data.getFeatures();
-                        int rows = data.getRows();
+                IgniteBiFunction<SimpleLabeledDatasetData, AlgorithmSpecificPartitionContext, SimpleLabeledDatasetData> builderFun = (data, ctx) -> {
+                    double[] features = data.getFeatures();
+                    int rows = data.getRows();
 
-                        // Makes a copy of features to supplement it by columns with values equal to 1.0.
-                        double[] a = new double[features.length + rows];
+                    // Makes a copy of features to supplement it by columns with values equal to 1.0.
+                    double[] a = new double[features.length + rows];
+                    Arrays.fill(a, 1.0);
 
-                        for (int i = 0; i < rows; i++)
-                            a[i] = 1.0;
+                    System.arraycopy(features, 0, a, rows, features.length);
 
-                        System.arraycopy(features, 0, a, rows, features.length);
+                    return new SimpleLabeledDatasetData(a, data.getLabels(), rows);
+                };
 
-                        return new SimpleLabeledDatasetData(a, data.getLabels(), rows);
-                    })
+                try (AlgorithmSpecificDataset dataset = DatasetFactory.create(
+                    ignite,
+                    persons,
+                    (env, upstream, upstreamSize) -> new AlgorithmSpecificPartitionContext(),
+                    builder.andThen(builderFun)
                 ).wrap(AlgorithmSpecificDataset::new)) {
                     // Trains linear regression model using gradient descent.
                     double[] linearRegressionMdl = new double[2];
@@ -122,10 +124,11 @@ public class AlgorithmSpecificDatasetExample {
                 }
 
                 System.out.println(">>> Algorithm Specific Dataset example completed.");
-            }
-            finally {
+            } finally {
                 persons.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/dataset/CacheBasedDatasetExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/dataset/CacheBasedDatasetExample.java
index f9cb0cf..cb8a990 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/dataset/CacheBasedDatasetExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/dataset/CacheBasedDatasetExample.java
@@ -67,8 +67,9 @@ public class CacheBasedDatasetExample {
             } finally {
                 persons.destroy();
             }
+        } finally {
+            System.out.flush();
         }
-
     }
 
     /** */
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/inference/IgniteModelDistributedInferenceExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/inference/IgniteModelDistributedInferenceExample.java
index 7126c69..19535d0 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/inference/IgniteModelDistributedInferenceExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/inference/IgniteModelDistributedInferenceExample.java
@@ -17,6 +17,10 @@
 
 package org.apache.ignite.examples.ml.inference;
 
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import javax.cache.Cache;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -37,11 +41,6 @@ import org.apache.ignite.ml.regressions.linear.LinearRegressionModel;
 import org.apache.ignite.ml.util.MLSandboxDatasets;
 import org.apache.ignite.ml.util.SandboxMLCache;
 
-import javax.cache.Cache;
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
 /**
  * This example is based on {@link LinearRegressionLSQRTrainerExample}, but to perform inference it uses an approach
  * implemented in {@link org.apache.ignite.ml.inference} package.
@@ -101,6 +100,8 @@ public class IgniteModelDistributedInferenceExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/inference/ModelStorageExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/inference/ModelStorageExample.java
index 3f1d923..4787360 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/inference/ModelStorageExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/inference/ModelStorageExample.java
@@ -82,6 +82,8 @@ public class ModelStorageExample {
                     System.out.println(i + " -> " + res);
                 }
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowDistributedInferenceExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowDistributedInferenceExample.java
index a81da7f..82b4f91 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowDistributedInferenceExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowDistributedInferenceExample.java
@@ -94,6 +94,8 @@ public class TensorFlowDistributedInferenceExample {
             long t1 = System.currentTimeMillis();
 
             System.out.println("Threaded model throughput: " + images.size() / ((t1 - t0) / 1000.0) + " req/sec");
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowLocalInferenceExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowLocalInferenceExample.java
index baa1f00..75b885f 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowLocalInferenceExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowLocalInferenceExample.java
@@ -81,5 +81,6 @@ public class TensorFlowLocalInferenceExample {
         long t1 = System.currentTimeMillis();
 
         System.out.println("Threaded model throughput: " + 1.0 * images.size() / ((t1 - t0) / 1000) + " req/sec");
+        System.out.flush();
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowThreadedInferenceExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowThreadedInferenceExample.java
index 900dcd4..b4fe6d5 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowThreadedInferenceExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/inference/TensorFlowThreadedInferenceExample.java
@@ -91,5 +91,6 @@ public class TensorFlowThreadedInferenceExample {
         long t1 = System.currentTimeMillis();
 
         System.out.println("Threaded model throughput: " + 1.0 * images.size() / ((t1 - t0) / 1000) + " req/sec");
+        System.out.flush();
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/knn/ANNClassificationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/knn/ANNClassificationExample.java
index a709a04..4fe5418 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/knn/ANNClassificationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/knn/ANNClassificationExample.java
@@ -124,6 +124,8 @@ public class ANNClassificationExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/knn/IrisClassificationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/knn/IrisClassificationExample.java
index d1de11e..5a7cc75 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/knn/IrisClassificationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/knn/IrisClassificationExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.knn;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -47,7 +47,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class IrisClassificationExample {
     /** Runs example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             System.out.println(">>> Ignite grid started.");
 
@@ -88,6 +88,8 @@ public class IrisClassificationExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/knn/KNNClassificationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/knn/KNNClassificationExample.java
index 7715bb2..07f5abd 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/knn/KNNClassificationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/knn/KNNClassificationExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.knn;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -41,14 +41,14 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  * After that it trains the model based on the specified data using
  * <a href="https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm">kNN</a> algorithm.</p>
  * <p>
- * Finally, this example loops over the test set of data points, applies the trained model to predict what cluster
- * does this point belong to, and compares prediction to expected outcome (ground truth).</p>
+ * Finally, this example loops over the test set of data points, applies the trained model to predict what cluster does
+ * this point belong to, and compares prediction to expected outcome (ground truth).</p>
  * <p>
  * You can change the test data used in this example and re-run it to explore this algorithm further.</p>
  */
 public class KNNClassificationExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> kNN multi-class classification algorithm over cached dataset usage example started.");
         // Start ignite grid.
@@ -76,8 +76,11 @@ public class KNNClassificationExample {
 
                 System.out.println("\n>>> Accuracy " + accuracy);
             } finally {
-                dataCache.destroy();
+                if (dataCache != null)
+                    dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/knn/KNNRegressionExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/knn/KNNRegressionExample.java
index e4ff356..79c36a7 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/knn/KNNRegressionExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/knn/KNNRegressionExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.knn;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -50,7 +50,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class KNNRegressionExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> kNN regression over cached dataset usage example started.");
         // Start ignite grid.
@@ -82,6 +82,8 @@ public class KNNRegressionExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/multiclass/OneVsRestClassificationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/multiclass/OneVsRestClassificationExample.java
index 56cddde..270ca7a 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/multiclass/OneVsRestClassificationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/multiclass/OneVsRestClassificationExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.multiclass;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.Arrays;
 import javax.cache.Cache;
 import org.apache.commons.math3.util.Precision;
@@ -57,7 +57,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class OneVsRestClassificationExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> One-vs-Rest SVM Multi-class classification model over cached dataset usage example started.");
         // Start ignite grid.
@@ -159,8 +159,11 @@ public class OneVsRestClassificationExample {
                     System.out.println(">>> One-vs-Rest SVM model over cache based dataset usage example completed.");
                 }
             } finally {
-                dataCache.destroy();
+                if (dataCache != null)
+                    dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/DiscreteNaiveBayesTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/DiscreteNaiveBayesTrainerExample.java
index b49be0e..e2a3ee1 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/DiscreteNaiveBayesTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/DiscreteNaiveBayesTrainerExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.naivebayes;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -47,8 +47,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class DiscreteNaiveBayesTrainerExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
-        System.out.println();
+    public static void main(String[] args) throws IOException {
         System.out.println(">>> Discrete naive Bayes classification model over partitioned dataset usage example started.");
         // Start ignite grid.
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
@@ -80,8 +79,11 @@ public class DiscreteNaiveBayesTrainerExample {
 
                 System.out.println(">>> Discrete Naive bayes model over partitioned dataset usage example completed.");
             } finally {
-                dataCache.destroy();
+                if (dataCache != null)
+                    dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/GaussianNaiveBayesTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/GaussianNaiveBayesTrainerExample.java
index fb095e6..e117bb0 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/GaussianNaiveBayesTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/naivebayes/GaussianNaiveBayesTrainerExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.naivebayes;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -47,7 +47,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class GaussianNaiveBayesTrainerExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> Naive Bayes classification model over partitioned dataset usage example started.");
         // Start ignite grid.
@@ -81,6 +81,8 @@ public class GaussianNaiveBayesTrainerExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/nn/MLPTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/nn/MLPTrainerExample.java
index c137898..b777ab7 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/nn/MLPTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/nn/MLPTrainerExample.java
@@ -130,6 +130,8 @@ public class MLPTrainerExample {
             } finally {
                 trainingSet.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/BinarizationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/BinarizationExample.java
index da122d5..3257ef3 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/BinarizationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/BinarizationExample.java
@@ -71,6 +71,8 @@ public class BinarizationExample {
             } finally {
                 data.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/ImputingExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/ImputingExample.java
index e36e38b..ee47976 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/ImputingExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/ImputingExample.java
@@ -71,6 +71,8 @@ public class ImputingExample {
             } finally {
                 data.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/MaxAbsScalerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/MaxAbsScalerExample.java
index 8601a8d..9adc36d 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/MaxAbsScalerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/MaxAbsScalerExample.java
@@ -62,10 +62,12 @@ public class MaxAbsScalerExample {
                     new DatasetHelper(dataset).describe();
                 }
 
-                System.out.println(">>> Imputing example completed.");
+                System.out.println(">>> Max abs example completed.");
             } finally {
                 data.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/MinMaxScalerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/MinMaxScalerExample.java
index a7cc6aa..e725918 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/MinMaxScalerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/MinMaxScalerExample.java
@@ -71,10 +71,12 @@ public class MinMaxScalerExample {
                     new DatasetHelper(dataset).describe();
                 }
 
-                System.out.println(">>> Imputing example completed.");
+                System.out.println(">>> MinMax preprocessing example completed.");
             } finally {
                 data.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/NormalizationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/NormalizationExample.java
index c3706c3..488e93d 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/NormalizationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/NormalizationExample.java
@@ -72,6 +72,8 @@ public class NormalizationExample {
             } finally {
                 data.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/StandardScalerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/StandardScalerExample.java
index 0581f63..280b6de 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/StandardScalerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/preprocessing/StandardScalerExample.java
@@ -62,10 +62,12 @@ public class StandardScalerExample {
                     new DatasetHelper(dataset).describe();
                 }
 
-                System.out.println(">>> Imputing example completed.");
+                System.out.println(">>> Standard scaler example completed.");
             } finally {
                 data.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/BostonHousePricesPredictionExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/BostonHousePricesPredictionExample.java
index 57e65e7..c4d13ea 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/BostonHousePricesPredictionExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/BostonHousePricesPredictionExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.regression.linear;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.function.BiFunction;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -48,7 +48,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class BostonHousePricesPredictionExample {
     /** Runs example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             System.out.println(">>> Ignite grid started.");
 
@@ -85,8 +85,11 @@ public class BostonHousePricesPredictionExample {
                 System.out.println(">>> Model: " + toString(mdl));
                 System.out.println(">>> R^2 score: " + score);
             } finally {
-                dataCache.destroy();
+                if (dataCache != null)
+                    dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionLSQRTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionLSQRTrainerExample.java
index 7f1c993..3bc3885 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionLSQRTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionLSQRTrainerExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.regression.linear;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -46,7 +46,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class LinearRegressionLSQRTrainerExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> Linear regression model over cache based dataset usage example started.");
         // Start ignite grid.
@@ -70,15 +70,15 @@ public class LinearRegressionLSQRTrainerExample {
                 // DatasetTrainer#fit(Ignite, IgniteCache, IgniteBiFunction, IgniteBiFunction) method call
                 // where there is a separate lambda for extracting label from (key, value) and a separate labmda for
                 // extracting features.
-                Vectorizer<Integer, Vector, Integer, Double> vectorizer = new DummyVectorizer<Integer>()
-                    .labeled(Vectorizer.LabelCoordinate.FIRST);
 
-                LinearRegressionModel mdl = trainer.fit(ignite, dataCache, vectorizer);
+                LinearRegressionModel mdl = trainer.fit(ignite, dataCache, new DummyVectorizer<Integer>()
+                    .labeled(Vectorizer.LabelCoordinate.FIRST));
 
                 double rmse = Evaluator.evaluate(
                     dataCache,
                     mdl,
-                    vectorizer,
+                    new DummyVectorizer<Integer>()
+                        .labeled(Vectorizer.LabelCoordinate.FIRST),
                     new RegressionMetrics()
                 );
 
@@ -88,6 +88,8 @@ public class LinearRegressionLSQRTrainerExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionLSQRTrainerWithMinMaxScalerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionLSQRTrainerWithMinMaxScalerExample.java
index ba109d3..ef40fe6 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionLSQRTrainerWithMinMaxScalerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionLSQRTrainerWithMinMaxScalerExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.regression.linear;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -52,7 +52,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class LinearRegressionLSQRTrainerWithMinMaxScalerExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> Linear regression model with Min Max Scaling preprocessor over cached dataset usage example started.");
         // Start ignite grid.
@@ -97,8 +97,11 @@ public class LinearRegressionLSQRTrainerWithMinMaxScalerExample {
                 System.out.println(">>> ---------------------------------");
                 System.out.println(">>> Linear regression model with MinMaxScaler preprocessor over cache based dataset usage example completed.");
             } finally {
-                dataCache.destroy();
+                if (dataCache != null)
+                    dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionSGDTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionSGDTrainerExample.java
index dbb287a..b7a3f31 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionSGDTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/regression/linear/LinearRegressionSGDTrainerExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.regression.linear;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -51,7 +51,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class LinearRegressionSGDTrainerExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> Linear regression model over sparse distributed matrix API usage example started.");
         // Start ignite grid.
@@ -92,6 +92,8 @@ public class LinearRegressionSGDTrainerExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/bagged/BaggedLogisticRegressionSGDTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/bagged/BaggedLogisticRegressionSGDTrainerExample.java
index 651bd4f..935c54b 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/bagged/BaggedLogisticRegressionSGDTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/bagged/BaggedLogisticRegressionSGDTrainerExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.regression.logistic.bagged;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.Arrays;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -54,7 +54,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class BaggedLogisticRegressionSGDTrainerExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> Logistic regression model over partitioned dataset usage example started.");
         // Start ignite grid.
@@ -93,14 +93,15 @@ public class BaggedLogisticRegressionSGDTrainerExample {
                 Vectorizer<Integer, Vector, Integer, Double> vectorizer = new DummyVectorizer<Integer>()
                     .labeled(Vectorizer.LabelCoordinate.FIRST);
 
-                double[] score = new CrossValidation<BaggedModel, Double, Integer, Vector>().score(
-                    baggedTrainer,
-                    new Accuracy<>(),
-                    ignite,
-                    dataCache,
-                    vectorizer,
-                    3
-                );
+                double[] score = new CrossValidation<BaggedModel, Double, Integer, Vector>()
+                    .withIgnite(ignite)
+                    .withUpstreamCache(dataCache)
+                    .withTrainer(baggedTrainer)
+                    .withMetric(new Accuracy<>())
+                    .withPreprocessor(vectorizer)
+                    .withAmountOfFolds(3)
+                    .isRunningOnPipeline(false)
+                    .scoreByFolds();
 
                 System.out.println(">>> ---------------------------------");
 
@@ -108,8 +109,11 @@ public class BaggedLogisticRegressionSGDTrainerExample {
 
                 System.out.println(">>> Bagged logistic regression model over partitioned dataset usage example completed.");
             } finally {
-                dataCache.destroy();
+                if (dataCache != null)
+                    dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/binary/LogisticRegressionSGDTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/binary/LogisticRegressionSGDTrainerExample.java
index d7ec506..e3441ec 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/binary/LogisticRegressionSGDTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/regression/logistic/binary/LogisticRegressionSGDTrainerExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.regression.logistic.binary;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -50,7 +50,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class LogisticRegressionSGDTrainerExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> Logistic regression model over partitioned dataset usage example started.");
         // Start ignite grid.
@@ -91,8 +91,11 @@ public class LogisticRegressionSGDTrainerExample {
 
                 System.out.println(">>> Logistic regression model over partitioned dataset usage example completed.");
             } finally {
-                dataCache.destroy();
+                if (dataCache != null)
+                    dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/selection/cv/CrossValidationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/selection/cv/CrossValidationExample.java
index 6e068fc..514ed6b 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/selection/cv/CrossValidationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/selection/cv/CrossValidationExample.java
@@ -76,17 +76,19 @@ public class CrossValidationExample {
                 DecisionTreeClassificationTrainer trainer = new DecisionTreeClassificationTrainer(4, 0);
 
                 LabeledDummyVectorizer<Integer, Double> vectorizer = new LabeledDummyVectorizer<>();
+
                 CrossValidation<DecisionTreeNode, Double, Integer, LabeledVector<Double>> scoreCalculator
                     = new CrossValidation<>();
 
-                double[] accuracyScores = scoreCalculator.score(
-                    trainer,
-                    new Accuracy<>(),
-                    ignite,
-                    trainingSet,
-                    vectorizer,
-                    4
-                );
+                double[] accuracyScores = scoreCalculator
+                    .withIgnite(ignite)
+                    .withUpstreamCache(trainingSet)
+                    .withTrainer(trainer)
+                    .withMetric(new Accuracy<>())
+                    .withPreprocessor(vectorizer)
+                    .withAmountOfFolds(4)
+                    .isRunningOnPipeline(false)
+                    .scoreByFolds();
 
                 System.out.println(">>> Accuracy: " + Arrays.toString(accuracyScores));
 
@@ -95,14 +97,9 @@ public class CrossValidationExample {
                     .withPositiveClsLb(1.0)
                     .withMetric(BinaryClassificationMetricValues::balancedAccuracy);
 
-                double[] balancedAccuracyScores = scoreCalculator.score(
-                    trainer,
-                    metrics,
-                    ignite,
-                    trainingSet,
-                    vectorizer,
-                    4
-                );
+                double[] balancedAccuracyScores = scoreCalculator
+                    .withMetric(metrics)
+                    .scoreByFolds();
 
                 System.out.println(">>> Balanced Accuracy: " + Arrays.toString(balancedAccuracyScores));
 
@@ -110,6 +107,8 @@ public class CrossValidationExample {
             } finally {
                 trainingSet.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/EvaluatorExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/EvaluatorExample.java
index 54436325..b9638ca 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/EvaluatorExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/EvaluatorExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.selection.scoring;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -47,7 +47,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class EvaluatorExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> kNN multi-class classification algorithm over cached dataset usage example started.");
         // Start ignite grid.
@@ -84,6 +84,8 @@ public class EvaluatorExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/MultipleMetricsExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/MultipleMetricsExample.java
index a410e0d..e213bb0 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/MultipleMetricsExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/MultipleMetricsExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.selection.scoring;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.Map;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -48,7 +48,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class MultipleMetricsExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         // Start ignite grid.
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             System.out.println(">>> Ignite grid started.");
@@ -76,6 +76,8 @@ public class MultipleMetricsExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/RegressionMetricExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/RegressionMetricExample.java
index 9ace1ef..e5e630a 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/RegressionMetricExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/selection/scoring/RegressionMetricExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.selection.scoring;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -48,7 +48,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class RegressionMetricExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> kNN regression over cached dataset usage example started.");
         // Start ignite grid.
@@ -79,6 +79,8 @@ public class RegressionMetricExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/selection/split/TrainTestDatasetSplitterExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/selection/split/TrainTestDatasetSplitterExample.java
index c28edb9..17f53e3 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/selection/split/TrainTestDatasetSplitterExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/selection/split/TrainTestDatasetSplitterExample.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.examples.ml.selection.split;
 
+import java.io.IOException;
+import javax.cache.Cache;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -32,9 +34,6 @@ import org.apache.ignite.ml.selection.split.TrainTestSplit;
 import org.apache.ignite.ml.util.MLSandboxDatasets;
 import org.apache.ignite.ml.util.SandboxMLCache;
 
-import javax.cache.Cache;
-import java.io.FileNotFoundException;
-
 /**
  * Run linear regression model over dataset split on train and test subsets ({@link TrainTestDatasetSplitter}).
  * <p>
@@ -51,7 +50,7 @@ import java.io.FileNotFoundException;
  */
 public class TrainTestDatasetSplitterExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> Linear regression model over cache based dataset usage example started.");
         // Start ignite grid.
@@ -100,6 +99,8 @@ public class TrainTestDatasetSplitterExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/sql/DecisionTreeClassificationTrainerSQLInferenceExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/sql/DecisionTreeClassificationTrainerSQLInferenceExample.java
index 926512e..7bf6d1d 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/sql/DecisionTreeClassificationTrainerSQLInferenceExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/sql/DecisionTreeClassificationTrainerSQLInferenceExample.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.examples.ml.sql;
 
+import java.util.List;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -31,8 +32,6 @@ import org.apache.ignite.ml.sql.SqlDatasetBuilder;
 import org.apache.ignite.ml.tree.DecisionTreeClassificationTrainer;
 import org.apache.ignite.ml.tree.DecisionTreeNode;
 
-import java.util.List;
-
 /**
  * Example of using distributed {@link DecisionTreeClassificationTrainer} on a data stored in SQL table and inference
  * made as SQL select query.
@@ -139,6 +138,8 @@ public class DecisionTreeClassificationTrainerSQLInferenceExample {
                 cache.query(new SqlFieldsQuery("DROP TABLE titanik_test"));
                 cache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/sql/DecisionTreeClassificationTrainerSQLTableExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/sql/DecisionTreeClassificationTrainerSQLTableExample.java
index 23e4204..93e02ba 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/sql/DecisionTreeClassificationTrainerSQLTableExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/sql/DecisionTreeClassificationTrainerSQLTableExample.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.examples.ml.sql;
 
+import java.util.List;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -31,8 +32,6 @@ import org.apache.ignite.ml.sql.SqlDatasetBuilder;
 import org.apache.ignite.ml.tree.DecisionTreeClassificationTrainer;
 import org.apache.ignite.ml.tree.DecisionTreeNode;
 
-import java.util.List;
-
 /**
  * Example of using distributed {@link DecisionTreeClassificationTrainer} on a data stored in SQL table.
  */
@@ -142,6 +141,8 @@ public class DecisionTreeClassificationTrainerSQLTableExample {
                 cache.query(new SqlFieldsQuery("DROP TABLE titanik_test"));
                 cache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/svm/SVMBinaryClassificationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/svm/SVMBinaryClassificationExample.java
index 9a19b5e..78422d4 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/svm/SVMBinaryClassificationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/svm/SVMBinaryClassificationExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.svm;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -46,7 +46,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  */
 public class SVMBinaryClassificationExample {
     /** Run example. */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> SVM Binary classification model over cached dataset usage example started.");
         // Start ignite grid.
@@ -78,6 +78,8 @@ public class SVMBinaryClassificationExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tree/DecisionTreeClassificationTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/tree/DecisionTreeClassificationTrainerExample.java
index 9787719..a049703 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tree/DecisionTreeClassificationTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tree/DecisionTreeClassificationTrainerExample.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.examples.ml.tree;
 
+import java.util.Random;
 import org.apache.commons.math3.util.Precision;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -29,8 +30,6 @@ import org.apache.ignite.ml.structures.LabeledVector;
 import org.apache.ignite.ml.tree.DecisionTreeClassificationTrainer;
 import org.apache.ignite.ml.tree.DecisionTreeNode;
 
-import java.util.Random;
-
 /**
  * Example of using distributed {@link DecisionTreeClassificationTrainer}.
  * <p>
@@ -104,6 +103,8 @@ public class DecisionTreeClassificationTrainerExample {
             } finally {
                 trainingSet.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tree/DecisionTreeRegressionTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/tree/DecisionTreeRegressionTrainerExample.java
index 568aac3..e7a3c6a 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tree/DecisionTreeRegressionTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tree/DecisionTreeRegressionTrainerExample.java
@@ -91,6 +91,8 @@ public class DecisionTreeRegressionTrainerExample {
             } finally {
                 trainingSet.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tree/FraudDetectionExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/tree/FraudDetectionExample.java
index 84d0afd..4d38ebf 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tree/FraudDetectionExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tree/FraudDetectionExample.java
@@ -17,7 +17,7 @@
 
 package org.apache.ignite.examples.ml.tree;
 
-import java.io.FileNotFoundException;
+import java.io.IOException;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -48,7 +48,7 @@ import org.apache.ignite.ml.util.SandboxMLCache;
  * Description of entropy can be found in: https://en.wikipedia.org/wiki/Evaluation_of_binary_classifiers .
  */
 public class FraudDetectionExample {
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             System.out.println(">>> Ignite grid started.");
 
@@ -78,10 +78,11 @@ public class FraudDetectionExample {
                         .withEnvironmentBuilder(LearningEnvironmentBuilder.defaultBuilder().withRNGSeed(0)),
                     vectorizer, split
                 );
-            }
-            finally {
+            } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tree/boosting/GDBOnTreesClassificationTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/tree/boosting/GDBOnTreesClassificationTrainerExample.java
index f9d5be4..3fd0f41 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tree/boosting/GDBOnTreesClassificationTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tree/boosting/GDBOnTreesClassificationTrainerExample.java
@@ -87,6 +87,8 @@ public class GDBOnTreesClassificationTrainerExample {
             } finally {
                 trainingSet.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tree/boosting/GDBOnTreesRegressionTrainerExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/tree/boosting/GDBOnTreesRegressionTrainerExample.java
index edc3eee..a2b7ed5 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tree/boosting/GDBOnTreesRegressionTrainerExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tree/boosting/GDBOnTreesRegressionTrainerExample.java
@@ -86,6 +86,8 @@ public class GDBOnTreesRegressionTrainerExample {
             } finally {
                 trainingSet.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestClassificationExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestClassificationExample.java
index 13e6792..e2488aa 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestClassificationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestClassificationExample.java
@@ -17,6 +17,11 @@
 
 package org.apache.ignite.examples.ml.tree.randomforest;
 
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import javax.cache.Cache;
 import org.apache.commons.math3.util.Precision;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -33,12 +38,6 @@ import org.apache.ignite.ml.tree.randomforest.data.FeaturesCountSelectionStrateg
 import org.apache.ignite.ml.util.MLSandboxDatasets;
 import org.apache.ignite.ml.util.SandboxMLCache;
 
-import javax.cache.Cache;
-import java.io.FileNotFoundException;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
 /**
  * Example represents a solution for the task of wine classification based on a
  *  <a href ="https://en.wikipedia.org/wiki/Random_forest">Random Forest</a> implementation for
@@ -59,7 +58,7 @@ public class RandomForestClassificationExample {
     /**
      * Run example.
      */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> Random Forest multi-class classification algorithm over cached dataset usage example started.");
         // Start ignite grid.
@@ -113,8 +112,11 @@ public class RandomForestClassificationExample {
                 }
 
             } finally {
-                dataCache.destroy();
+                if (dataCache != null)
+                    dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestRegressionExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestRegressionExample.java
index 42f818e..4f27b85 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestRegressionExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tree/randomforest/RandomForestRegressionExample.java
@@ -17,6 +17,11 @@
 
 package org.apache.ignite.examples.ml.tree.randomforest;
 
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import javax.cache.Cache;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
@@ -35,12 +40,6 @@ import org.apache.ignite.ml.tree.randomforest.data.FeaturesCountSelectionStrateg
 import org.apache.ignite.ml.util.MLSandboxDatasets;
 import org.apache.ignite.ml.util.SandboxMLCache;
 
-import javax.cache.Cache;
-import java.io.FileNotFoundException;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
 /**
  * Example represents a solution for the task of price predictions for houses in Boston based on a
  * <a href ="https://en.wikipedia.org/wiki/Random_forest">Random Forest</a> implementation for regression.
@@ -61,7 +60,7 @@ public class RandomForestRegressionExample {
     /**
      * Run example.
      */
-    public static void main(String[] args) throws FileNotFoundException {
+    public static void main(String[] args) throws IOException {
         System.out.println();
         System.out.println(">>> Random Forest regression algorithm over cached dataset usage example started.");
         // Start ignite grid.
@@ -127,6 +126,8 @@ public class RandomForestRegressionExample {
             } finally {
                 dataCache.destroy();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_1_Read_and_Learn.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_1_Read_and_Learn.java
index 331aeee..cd9cff6 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_1_Read_and_Learn.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_1_Read_and_Learn.java
@@ -73,10 +73,11 @@ public class Step_1_Read_and_Learn {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 1 (read and learn) example completed.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_2_Imputing.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_2_Imputing.java
index a270c00..ef5f5d3 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_2_Imputing.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_2_Imputing.java
@@ -83,10 +83,11 @@ public class Step_2_Imputing {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 2 (imputing) example completed.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_3_Categorial.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_3_Categorial.java
index e6fb3cd..9ac3290 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_3_Categorial.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_3_Categorial.java
@@ -67,7 +67,7 @@ public class Step_3_Categorial {
                     .fit(ignite,
                         dataCache,
                         vectorizer
-                );
+                    );
 
                 Preprocessor<Integer, Vector> imputingPreprocessor = new ImputerTrainer<Integer, Vector>()
                     .fit(ignite,
@@ -97,10 +97,11 @@ public class Step_3_Categorial {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 3 (categorial) example completed.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_3_Categorial_with_One_Hot_Encoder.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_3_Categorial_with_One_Hot_Encoder.java
index 92a7714..29e45a4 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_3_Categorial_with_One_Hot_Encoder.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_3_Categorial_with_One_Hot_Encoder.java
@@ -69,7 +69,7 @@ public class Step_3_Categorial_with_One_Hot_Encoder {
                     .fit(ignite,
                         dataCache,
                         vectorizer
-                );
+                    );
 
                 Preprocessor<Integer, Vector> imputingPreprocessor = new ImputerTrainer<Integer, Vector>()
                     .fit(ignite,
@@ -100,10 +100,11 @@ public class Step_3_Categorial_with_One_Hot_Encoder {
 
                 System.out.println(">>> Tutorial step 3 (categorial with One-hot encoder) example started.");
 
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_4_Add_age_fare.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_4_Add_age_fare.java
index 9d42a1f..3975056 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_4_Add_age_fare.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_4_Add_age_fare.java
@@ -66,7 +66,7 @@ public class Step_4_Add_age_fare {
                     .fit(ignite,
                         dataCache,
                         vectorizer
-                );
+                    );
 
                 Preprocessor<Integer, Vector> imputingPreprocessor = new ImputerTrainer<Integer, Vector>()
                     .fit(ignite,
@@ -96,10 +96,11 @@ public class Step_4_Add_age_fare {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 4 (add age and fare) example completed.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_5_Scaling.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_5_Scaling.java
index 4fbf727..a40acfb 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_5_Scaling.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_5_Scaling.java
@@ -69,7 +69,7 @@ public class Step_5_Scaling {
                     .fit(ignite,
                         dataCache,
                         vectorizer
-                );
+                    );
 
                 Preprocessor<Integer, Vector> imputingPreprocessor = new ImputerTrainer<Integer, Vector>()
                     .fit(ignite,
@@ -114,10 +114,11 @@ public class Step_5_Scaling {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 5 (scaling) example completed.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_5_Scaling_with_Pipeline.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_5_Scaling_with_Pipeline.java
index 802359d..f62a244 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_5_Scaling_with_Pipeline.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_5_Scaling_with_Pipeline.java
@@ -88,10 +88,11 @@ public class Step_5_Scaling_with_Pipeline {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 5 (scaling) via Pipeline example completed.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_6_KNN.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_6_KNN.java
index ad33c41..6116764 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_6_KNN.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_6_KNN.java
@@ -115,10 +115,11 @@ public class Step_6_KNN {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 6 (kNN) example completed.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_7_Split_train_test.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_7_Split_train_test.java
index 69de194..1d239c9 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_7_Split_train_test.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_7_Split_train_test.java
@@ -98,6 +98,7 @@ public class Step_7_Split_train_test {
                         minMaxScalerPreprocessor
                     );
 
+
                 DecisionTreeClassificationTrainer trainer = new DecisionTreeClassificationTrainer(5, 0);
 
                 // Train decision tree model.
@@ -122,10 +123,11 @@ public class Step_7_Split_train_test {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 7 (split to train and test) example completed.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV.java
index aa6f12c..4a6caf6 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV.java
@@ -102,6 +102,7 @@ public class Step_8_CV {
                         imputingPreprocessor
                     );
 
+
                 // Tune hyperparams with K-fold Cross-Validation on the split training set.
                 int[] pSet = new int[]{1, 2};
                 int[] maxDeepSet = new int[]{1, 2, 3, 4, 5, 10, 20};
@@ -126,15 +127,16 @@ public class Step_8_CV {
                         CrossValidation<DecisionTreeNode, Double, Integer, Vector> scoreCalculator
                             = new CrossValidation<>();
 
-                        double[] scores = scoreCalculator.score(
-                            trainer,
-                            new Accuracy<>(),
-                            ignite,
-                            dataCache,
-                            split.getTrainFilter(),
-                            normalizationPreprocessor,
-                            3
-                        );
+                        double[] scores = scoreCalculator
+                            .withIgnite(ignite)
+                            .withUpstreamCache(dataCache)
+                            .withTrainer(trainer)
+                            .withMetric(new Accuracy<>())
+                            .withFilter(split.getTrainFilter())
+                            .withPreprocessor(normalizationPreprocessor)
+                            .withAmountOfFolds(3)
+                            .isRunningOnPipeline(false)
+                            .scoreByFolds();
 
                         System.out.println("Scores are: " + Arrays.toString(scores));
 
@@ -160,6 +162,7 @@ public class Step_8_CV {
                         minMaxScalerPreprocessor
                     );
 
+
                 DecisionTreeClassificationTrainer trainer = new DecisionTreeClassificationTrainer(bestMaxDeep, 0);
 
                 // Train decision tree model.
@@ -184,10 +187,11 @@ public class Step_8_CV {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 8 (cross-validation) example completed.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid.java
index 8b9f365..b7bc03d 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid.java
@@ -120,19 +120,21 @@ public class Step_8_CV_with_Param_Grid {
                     = new CrossValidation<>();
 
                 ParamGrid paramGrid = new ParamGrid()
-                    .addHyperParam("maxDeep", new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 10.0})
-                    .addHyperParam("minImpurityDecrease", new Double[]{0.0, 0.25, 0.5});
-
-                CrossValidationResult crossValidationRes = scoreCalculator.score(
-                    trainerCV,
-                    new Accuracy<>(),
-                    ignite,
-                    dataCache,
-                    split.getTrainFilter(),
-                    normalizationPreprocessor,
-                    3,
-                    paramGrid
-                );
+                    .addHyperParam("maxDeep", trainerCV::withMaxDeep, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 10.0})
+                    .addHyperParam("minImpurityDecrease", trainerCV::withMinImpurityDecrease, new Double[]{0.0, 0.25, 0.5});
+
+                scoreCalculator
+                    .withIgnite(ignite)
+                    .withUpstreamCache(dataCache)
+                    .withTrainer(trainerCV)
+                    .withMetric(new Accuracy<>())
+                    .withFilter(split.getTrainFilter())
+                    .isRunningOnPipeline(false)
+                    .withPreprocessor(normalizationPreprocessor)
+                    .withAmountOfFolds(3)
+                    .withParamGrid(paramGrid);
+
+                CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
 
                 System.out.println("Train with maxDeep: " + crossValidationRes.getBest("maxDeep")
                     + " and minImpurityDecrease: " + crossValidationRes.getBest("minImpurityDecrease"));
@@ -175,6 +177,8 @@ public class Step_8_CV_with_Param_Grid {
             } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
index 7dcc104..80d166e 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
@@ -122,24 +122,26 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                     = new CrossValidation<>();
 
                 ParamGrid paramGrid = new ParamGrid()
-                    .addHyperParam("maxDeep", new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0})
-                    .addHyperParam("minImpurityDecrease", new Double[] {0.0, 0.25, 0.5});
+                    .addHyperParam("maxDeep", trainerCV::withMaxDeep, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0})
+                    .addHyperParam("minImpurityDecrease", trainerCV::withMinImpurityDecrease, new Double[]{0.0, 0.25, 0.5});
 
                 BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
                     .withNegativeClsLb(0.0)
                     .withPositiveClsLb(1.0)
                     .withMetric(BinaryClassificationMetricValues::accuracy);
 
-                CrossValidationResult crossValidationRes = scoreCalculator.score(
-                    trainerCV,
-                    metrics,
-                    ignite,
-                    dataCache,
-                    split.getTrainFilter(),
-                    normalizationPreprocessor,
-                    3,
-                    paramGrid
-                );
+                scoreCalculator
+                    .withIgnite(ignite)
+                    .withUpstreamCache(dataCache)
+                    .withTrainer(trainerCV)
+                    .withMetric(metrics)
+                    .withFilter(split.getTrainFilter())
+                    .isRunningOnPipeline(false)
+                    .withPreprocessor(normalizationPreprocessor)
+                    .withAmountOfFolds(3)
+                    .withParamGrid(paramGrid);
+
+                CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
 
                 System.out.println("Train with maxDeep: " + crossValidationRes.getBest("maxDeep")
                     + " and minImpurityDecrease: " + crossValidationRes.getBest("minImpurityDecrease"));
@@ -179,10 +181,11 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics_and_pipeline.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics_and_pipeline.java
index 8bdc683..62c6737 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics_and_pipeline.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics_and_pipeline.java
@@ -80,11 +80,13 @@ public class Step_8_CV_with_Param_Grid_and_metrics_and_pipeline {
                 TrainTestSplit<Integer, Vector> split = new TrainTestDatasetSplitter<Integer, Vector>()
                     .split(0.75);
 
+                DecisionTreeClassificationTrainer trainer = new DecisionTreeClassificationTrainer(5, 0);
+
                 Pipeline<Integer, Vector, Integer, Double> pipeline = new Pipeline<Integer, Vector, Integer, Double>()
                     .addVectorizer(vectorizer)
                     .addPreprocessingTrainer(new ImputerTrainer<Integer, Vector>())
                     .addPreprocessingTrainer(new MinMaxScalerTrainer<Integer, Vector>())
-                    .addTrainer(new DecisionTreeClassificationTrainer(5, 0));
+                    .addTrainer(trainer);
 
                 // Tune hyperparams with K-fold Cross-Validation on the split training set.
 
@@ -92,23 +94,25 @@ public class Step_8_CV_with_Param_Grid_and_metrics_and_pipeline {
                     = new CrossValidation<>();
 
                 ParamGrid paramGrid = new ParamGrid()
-                    .addHyperParam("maxDeep", new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0})
-                    .addHyperParam("minImpurityDecrease", new Double[]{0.0, 0.25, 0.5});
+                    .addHyperParam("maxDeep", trainer::withMaxDeep, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0})
+                    .addHyperParam("minImpurityDecrease", trainer::withMinImpurityDecrease, new Double[]{0.0, 0.25, 0.5});
 
                 BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
                     .withNegativeClsLb(0.0)
                     .withPositiveClsLb(1.0)
                     .withMetric(BinaryClassificationMetricValues::accuracy);
 
-                CrossValidationResult crossValidationRes = scoreCalculator.score(
-                    pipeline,
-                    metrics,
-                    ignite,
-                    dataCache,
-                    split.getTrainFilter(),
-                    3,
-                    paramGrid
-                );
+                scoreCalculator
+                    .withIgnite(ignite)
+                    .withUpstreamCache(dataCache)
+                    .withPipeline(pipeline)
+                    .withMetric(metrics)
+                    .withFilter(split.getTrainFilter())
+                    .withPreprocessor(vectorizer)
+                    .withAmountOfFolds(3)
+                    .withParamGrid(paramGrid);
+
+                CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
 
                 System.out.println("Train with maxDeep: " + crossValidationRes.getBest("maxDeep")
                     + " and minImpurityDecrease: " + crossValidationRes.getBest("minImpurityDecrease"));
@@ -125,6 +129,8 @@ public class Step_8_CV_with_Param_Grid_and_metrics_and_pipeline {
             } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_9_Scaling_With_Stacking.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_9_Scaling_With_Stacking.java
index 55d553d..babef3b 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_9_Scaling_With_Stacking.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_9_Scaling_With_Stacking.java
@@ -108,14 +108,14 @@ public class Step_9_Scaling_With_Stacking {
 
                 StackedModel<Vector, Vector, Double, LogisticRegressionModel> mdl =
                     new StackedVectorDatasetTrainer<>(aggregator)
-                    .addTrainerWithDoubleOutput(trainer)
-                    .addTrainerWithDoubleOutput(trainer1)
-                    .addTrainerWithDoubleOutput(trainer2)
-                    .fit(
-                        ignite,
-                        dataCache,
-                        normalizationPreprocessor
-                    );
+                        .addTrainerWithDoubleOutput(trainer)
+                        .addTrainerWithDoubleOutput(trainer1)
+                        .addTrainerWithDoubleOutput(trainer2)
+                        .fit(
+                            ignite,
+                            dataCache,
+                            normalizationPreprocessor
+                        );
 
                 System.out.println("\n>>> Trained model: " + mdl);
 
@@ -130,10 +130,11 @@ public class Step_9_Scaling_With_Stacking {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 5 (scaling) example completed.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/TutorialStepByStepExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/TutorialStepByStepExample.java
index 24eb634..0c96a0f 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/TutorialStepByStepExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/TutorialStepByStepExample.java
@@ -17,6 +17,12 @@
 
 package org.apache.ignite.examples.ml.tutorial;
 
+import org.apache.ignite.examples.ml.tutorial.hyperparametertuning.Step_10_RandomSearch;
+import org.apache.ignite.examples.ml.tutorial.hyperparametertuning.Step_11_Parallel_BrutForce_Search;
+import org.apache.ignite.examples.ml.tutorial.hyperparametertuning.Step_12_Parallel_Random_Search;
+import org.apache.ignite.examples.ml.tutorial.hyperparametertuning.Step_13_Genetic_Programming_Search;
+import org.apache.ignite.examples.ml.tutorial.hyperparametertuning.Step_14_Parallel_Genetic_Programming_Search;
+
 /**
  * Run all the tutorial examples step by step with primary purpose to provide
  * automatic execution from {@code IgniteExamplesMLTestSuite}.
@@ -34,5 +40,11 @@ public class TutorialStepByStepExample {
         Step_7_Split_train_test.main(args);
         Step_8_CV.main(args);
         Step_8_CV_with_Param_Grid.main(args);
+        Step_9_Scaling_With_Stacking.main(args);
+        Step_10_RandomSearch.main(args);
+        Step_11_Parallel_BrutForce_Search.main(args);
+        Step_12_Parallel_Random_Search.main(args);
+        Step_13_Genetic_Programming_Search.main(args);
+        Step_14_Parallel_Genetic_Programming_Search.main(args);
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_10_RandomSearch.java
similarity index 82%
copy from examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
copy to examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_10_RandomSearch.java
index 7dcc104..dcafedc 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_10_RandomSearch.java
@@ -15,13 +15,14 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.ml.tutorial;
+package org.apache.ignite.examples.ml.tutorial.hyperparametertuning;
 
 import java.io.FileNotFoundException;
 import java.util.Arrays;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
+import org.apache.ignite.examples.ml.tutorial.TitanicUtils;
 import org.apache.ignite.ml.dataset.feature.extractor.Vectorizer;
 import org.apache.ignite.ml.dataset.feature.extractor.impl.DummyVectorizer;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
@@ -34,6 +35,7 @@ import org.apache.ignite.ml.preprocessing.normalization.NormalizationTrainer;
 import org.apache.ignite.ml.selection.cv.CrossValidation;
 import org.apache.ignite.ml.selection.cv.CrossValidationResult;
 import org.apache.ignite.ml.selection.paramgrid.ParamGrid;
+import org.apache.ignite.ml.selection.paramgrid.RandomStrategy;
 import org.apache.ignite.ml.selection.scoring.evaluator.Evaluator;
 import org.apache.ignite.ml.selection.scoring.metric.classification.Accuracy;
 import org.apache.ignite.ml.selection.scoring.metric.classification.BinaryClassificationMetricValues;
@@ -67,12 +69,9 @@ import org.apache.ignite.ml.tree.DecisionTreeNode;
  * <p>
  * All scenarios are described there: https://sebastianraschka.com/faq/docs/evaluate-a-model.html</p>
  */
-public class Step_8_CV_with_Param_Grid_and_metrics {
+public class Step_10_RandomSearch {
     /** Run example. */
     public static void main(String[] args) {
-        System.out.println();
-        System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             try {
                 IgniteCache<Integer, Vector> dataCache = TitanicUtils.readPassengers(ignite);
@@ -87,7 +86,7 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 Preprocessor<Integer, Vector> strEncoderPreprocessor = new EncoderTrainer<Integer, Vector>()
                     .withEncoderType(EncoderType.STRING_ENCODER)
                     .withEncodedFeature(1)
-                    .withEncodedFeature(6) // <--- Changed index here.
+                    .withEncodedFeature(6)
                     .fit(ignite,
                         dataCache,
                         vectorizer
@@ -106,8 +105,10 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                         imputingPreprocessor
                     );
 
-                Preprocessor<Integer, Vector> normalizationPreprocessor = new NormalizationTrainer<Integer, Vector>()
-                    .withP(1)
+                NormalizationTrainer<Integer, Vector> normalizationTrainer = new NormalizationTrainer<Integer, Vector>()
+                    .withP(1);
+
+                Preprocessor<Integer, Vector> normalizationPreprocessor = normalizationTrainer
                     .fit(
                         ignite,
                         dataCache,
@@ -122,24 +123,32 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                     = new CrossValidation<>();
 
                 ParamGrid paramGrid = new ParamGrid()
-                    .addHyperParam("maxDeep", new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0})
-                    .addHyperParam("minImpurityDecrease", new Double[] {0.0, 0.25, 0.5});
+                    .withParameterSearchStrategy(
+                        new RandomStrategy()
+                            .withMaxTries(10)
+                            .withSeed(12L)
+                    )
+                    .addHyperParam("p", normalizationTrainer::withP, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0})
+                    .addHyperParam("maxDeep", trainerCV::withMaxDeep, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0})
+                    .addHyperParam("minImpurityDecrease", trainerCV::withMinImpurityDecrease, new Double[]{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0});
 
                 BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
                     .withNegativeClsLb(0.0)
                     .withPositiveClsLb(1.0)
                     .withMetric(BinaryClassificationMetricValues::accuracy);
 
-                CrossValidationResult crossValidationRes = scoreCalculator.score(
-                    trainerCV,
-                    metrics,
-                    ignite,
-                    dataCache,
-                    split.getTrainFilter(),
-                    normalizationPreprocessor,
-                    3,
-                    paramGrid
-                );
+                scoreCalculator
+                    .withIgnite(ignite)
+                    .withUpstreamCache(dataCache)
+                    .withTrainer(trainerCV)
+                    .withMetric(metrics)
+                    .withFilter(split.getTrainFilter())
+                    .isRunningOnPipeline(false)
+                    .withPreprocessor(normalizationPreprocessor)
+                    .withAmountOfFolds(3)
+                    .withParamGrid(paramGrid);
+
+                CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
 
                 System.out.println("Train with maxDeep: " + crossValidationRes.getBest("maxDeep")
                     + " and minImpurityDecrease: " + crossValidationRes.getBest("minImpurityDecrease"));
@@ -179,10 +188,11 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
-}
+}
\ No newline at end of file
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_11_Parallel_BrutForce_Search.java
similarity index 79%
copy from examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
copy to examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_11_Parallel_BrutForce_Search.java
index 7dcc104..3428627 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_11_Parallel_BrutForce_Search.java
@@ -15,15 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.ml.tutorial;
+package org.apache.ignite.examples.ml.tutorial.hyperparametertuning;
 
 import java.io.FileNotFoundException;
 import java.util.Arrays;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
+import org.apache.ignite.examples.ml.tutorial.TitanicUtils;
 import org.apache.ignite.ml.dataset.feature.extractor.Vectorizer;
 import org.apache.ignite.ml.dataset.feature.extractor.impl.DummyVectorizer;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
+import org.apache.ignite.ml.environment.logging.ConsoleLogger;
+import org.apache.ignite.ml.environment.parallelism.ParallelismStrategy;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.preprocessing.Preprocessor;
 import org.apache.ignite.ml.preprocessing.encoding.EncoderTrainer;
@@ -33,6 +37,7 @@ import org.apache.ignite.ml.preprocessing.minmaxscaling.MinMaxScalerTrainer;
 import org.apache.ignite.ml.preprocessing.normalization.NormalizationTrainer;
 import org.apache.ignite.ml.selection.cv.CrossValidation;
 import org.apache.ignite.ml.selection.cv.CrossValidationResult;
+import org.apache.ignite.ml.selection.paramgrid.BruteForceStrategy;
 import org.apache.ignite.ml.selection.paramgrid.ParamGrid;
 import org.apache.ignite.ml.selection.scoring.evaluator.Evaluator;
 import org.apache.ignite.ml.selection.scoring.metric.classification.Accuracy;
@@ -67,12 +72,9 @@ import org.apache.ignite.ml.tree.DecisionTreeNode;
  * <p>
  * All scenarios are described there: https://sebastianraschka.com/faq/docs/evaluate-a-model.html</p>
  */
-public class Step_8_CV_with_Param_Grid_and_metrics {
+public class Step_11_Parallel_BrutForce_Search {
     /** Run example. */
     public static void main(String[] args) {
-        System.out.println();
-        System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             try {
                 IgniteCache<Integer, Vector> dataCache = TitanicUtils.readPassengers(ignite);
@@ -87,7 +89,7 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 Preprocessor<Integer, Vector> strEncoderPreprocessor = new EncoderTrainer<Integer, Vector>()
                     .withEncoderType(EncoderType.STRING_ENCODER)
                     .withEncodedFeature(1)
-                    .withEncodedFeature(6) // <--- Changed index here.
+                    .withEncodedFeature(6)
                     .fit(ignite,
                         dataCache,
                         vectorizer
@@ -106,8 +108,11 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                         imputingPreprocessor
                     );
 
-                Preprocessor<Integer, Vector> normalizationPreprocessor = new NormalizationTrainer<Integer, Vector>()
-                    .withP(1)
+
+                NormalizationTrainer<Integer, Vector> normalizationTrainer = new NormalizationTrainer<Integer, Vector>()
+                    .withP(1);
+
+                Preprocessor<Integer, Vector> normalizationPreprocessor = normalizationTrainer
                     .fit(
                         ignite,
                         dataCache,
@@ -122,24 +127,32 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                     = new CrossValidation<>();
 
                 ParamGrid paramGrid = new ParamGrid()
-                    .addHyperParam("maxDeep", new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0})
-                    .addHyperParam("minImpurityDecrease", new Double[] {0.0, 0.25, 0.5});
+                    .withParameterSearchStrategy(new BruteForceStrategy())
+                    .addHyperParam("p", normalizationTrainer::withP, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0})
+                    .addHyperParam("maxDeep", trainerCV::withMaxDeep, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0})
+                    .addHyperParam("minImpurityDecrease", trainerCV::withMinImpurityDecrease, new Double[]{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0});
+
 
                 BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
                     .withNegativeClsLb(0.0)
                     .withPositiveClsLb(1.0)
                     .withMetric(BinaryClassificationMetricValues::accuracy);
 
-                CrossValidationResult crossValidationRes = scoreCalculator.score(
-                    trainerCV,
-                    metrics,
-                    ignite,
-                    dataCache,
-                    split.getTrainFilter(),
-                    normalizationPreprocessor,
-                    3,
-                    paramGrid
-                );
+                scoreCalculator
+                    .withIgnite(ignite)
+                    .withUpstreamCache(dataCache)
+                    .withEnvironmentBuilder(LearningEnvironmentBuilder.defaultBuilder()
+                        .withParallelismStrategyTypeDependency(ParallelismStrategy.ON_DEFAULT_POOL)
+                        .withLoggingFactoryDependency(ConsoleLogger.Factory.LOW))
+                    .withTrainer(trainerCV)
+                    .isRunningOnPipeline(false)
+                    .withMetric(metrics)
+                    .withFilter(split.getTrainFilter())
+                    .withPreprocessor(normalizationPreprocessor)
+                    .withAmountOfFolds(3)
+                    .withParamGrid(paramGrid);
+
+                CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
 
                 System.out.println("Train with maxDeep: " + crossValidationRes.getBest("maxDeep")
                     + " and minImpurityDecrease: " + crossValidationRes.getBest("minImpurityDecrease"));
@@ -179,10 +192,11 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
-}
+}
\ No newline at end of file
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_12_Parallel_Random_Search.java
similarity index 78%
copy from examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
copy to examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_12_Parallel_Random_Search.java
index 7dcc104..aaa3c15c 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_12_Parallel_Random_Search.java
@@ -15,15 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.ml.tutorial;
+package org.apache.ignite.examples.ml.tutorial.hyperparametertuning;
 
 import java.io.FileNotFoundException;
 import java.util.Arrays;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
+import org.apache.ignite.examples.ml.tutorial.TitanicUtils;
 import org.apache.ignite.ml.dataset.feature.extractor.Vectorizer;
 import org.apache.ignite.ml.dataset.feature.extractor.impl.DummyVectorizer;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
+import org.apache.ignite.ml.environment.logging.ConsoleLogger;
+import org.apache.ignite.ml.environment.parallelism.ParallelismStrategy;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.preprocessing.Preprocessor;
 import org.apache.ignite.ml.preprocessing.encoding.EncoderTrainer;
@@ -34,6 +38,7 @@ import org.apache.ignite.ml.preprocessing.normalization.NormalizationTrainer;
 import org.apache.ignite.ml.selection.cv.CrossValidation;
 import org.apache.ignite.ml.selection.cv.CrossValidationResult;
 import org.apache.ignite.ml.selection.paramgrid.ParamGrid;
+import org.apache.ignite.ml.selection.paramgrid.RandomStrategy;
 import org.apache.ignite.ml.selection.scoring.evaluator.Evaluator;
 import org.apache.ignite.ml.selection.scoring.metric.classification.Accuracy;
 import org.apache.ignite.ml.selection.scoring.metric.classification.BinaryClassificationMetricValues;
@@ -67,12 +72,9 @@ import org.apache.ignite.ml.tree.DecisionTreeNode;
  * <p>
  * All scenarios are described there: https://sebastianraschka.com/faq/docs/evaluate-a-model.html</p>
  */
-public class Step_8_CV_with_Param_Grid_and_metrics {
+public class Step_12_Parallel_Random_Search {
     /** Run example. */
     public static void main(String[] args) {
-        System.out.println();
-        System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             try {
                 IgniteCache<Integer, Vector> dataCache = TitanicUtils.readPassengers(ignite);
@@ -87,7 +89,7 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 Preprocessor<Integer, Vector> strEncoderPreprocessor = new EncoderTrainer<Integer, Vector>()
                     .withEncoderType(EncoderType.STRING_ENCODER)
                     .withEncodedFeature(1)
-                    .withEncodedFeature(6) // <--- Changed index here.
+                    .withEncodedFeature(6)
                     .fit(ignite,
                         dataCache,
                         vectorizer
@@ -106,8 +108,11 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                         imputingPreprocessor
                     );
 
-                Preprocessor<Integer, Vector> normalizationPreprocessor = new NormalizationTrainer<Integer, Vector>()
-                    .withP(1)
+
+                NormalizationTrainer<Integer, Vector> normalizationTrainer = new NormalizationTrainer<Integer, Vector>()
+                    .withP(1);
+
+                Preprocessor<Integer, Vector> normalizationPreprocessor = normalizationTrainer
                     .fit(
                         ignite,
                         dataCache,
@@ -122,24 +127,36 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                     = new CrossValidation<>();
 
                 ParamGrid paramGrid = new ParamGrid()
-                    .addHyperParam("maxDeep", new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0})
-                    .addHyperParam("minImpurityDecrease", new Double[] {0.0, 0.25, 0.5});
+                    .withParameterSearchStrategy(
+                        new RandomStrategy()
+                            .withMaxTries(10)
+                            .withSeed(12L)
+                    )
+                    .addHyperParam("p", normalizationTrainer::withP, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0})
+                    .addHyperParam("maxDeep", trainerCV::withMaxDeep, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0})
+                    .addHyperParam("minImpurityDecrease", trainerCV::withMinImpurityDecrease, new Double[]{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0});
+
 
                 BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
                     .withNegativeClsLb(0.0)
                     .withPositiveClsLb(1.0)
                     .withMetric(BinaryClassificationMetricValues::accuracy);
 
-                CrossValidationResult crossValidationRes = scoreCalculator.score(
-                    trainerCV,
-                    metrics,
-                    ignite,
-                    dataCache,
-                    split.getTrainFilter(),
-                    normalizationPreprocessor,
-                    3,
-                    paramGrid
-                );
+                scoreCalculator
+                    .withIgnite(ignite)
+                    .withUpstreamCache(dataCache)
+                    .withEnvironmentBuilder(LearningEnvironmentBuilder.defaultBuilder()
+                        .withParallelismStrategyTypeDependency(ParallelismStrategy.ON_DEFAULT_POOL)
+                        .withLoggingFactoryDependency(ConsoleLogger.Factory.LOW))
+                    .withTrainer(trainerCV)
+                    .isRunningOnPipeline(false)
+                    .withMetric(metrics)
+                    .withFilter(split.getTrainFilter())
+                    .withPreprocessor(normalizationPreprocessor)
+                    .withAmountOfFolds(3)
+                    .withParamGrid(paramGrid);
+
+                CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
 
                 System.out.println("Train with maxDeep: " + crossValidationRes.getBest("maxDeep")
                     + " and minImpurityDecrease: " + crossValidationRes.getBest("minImpurityDecrease"));
@@ -179,10 +196,11 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
-}
+}
\ No newline at end of file
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_13_Genetic_Programming_Search.java
similarity index 83%
copy from examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
copy to examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_13_Genetic_Programming_Search.java
index 7dcc104..2deed1c 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_13_Genetic_Programming_Search.java
@@ -15,13 +15,14 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.ml.tutorial;
+package org.apache.ignite.examples.ml.tutorial.hyperparametertuning;
 
 import java.io.FileNotFoundException;
 import java.util.Arrays;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
+import org.apache.ignite.examples.ml.tutorial.TitanicUtils;
 import org.apache.ignite.ml.dataset.feature.extractor.Vectorizer;
 import org.apache.ignite.ml.dataset.feature.extractor.impl.DummyVectorizer;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
@@ -33,6 +34,7 @@ import org.apache.ignite.ml.preprocessing.minmaxscaling.MinMaxScalerTrainer;
 import org.apache.ignite.ml.preprocessing.normalization.NormalizationTrainer;
 import org.apache.ignite.ml.selection.cv.CrossValidation;
 import org.apache.ignite.ml.selection.cv.CrossValidationResult;
+import org.apache.ignite.ml.selection.paramgrid.EvolutionOptimizationStrategy;
 import org.apache.ignite.ml.selection.paramgrid.ParamGrid;
 import org.apache.ignite.ml.selection.scoring.evaluator.Evaluator;
 import org.apache.ignite.ml.selection.scoring.metric.classification.Accuracy;
@@ -67,12 +69,9 @@ import org.apache.ignite.ml.tree.DecisionTreeNode;
  * <p>
  * All scenarios are described there: https://sebastianraschka.com/faq/docs/evaluate-a-model.html</p>
  */
-public class Step_8_CV_with_Param_Grid_and_metrics {
+public class Step_13_Genetic_Programming_Search {
     /** Run example. */
     public static void main(String[] args) {
-        System.out.println();
-        System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             try {
                 IgniteCache<Integer, Vector> dataCache = TitanicUtils.readPassengers(ignite);
@@ -87,7 +86,7 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 Preprocessor<Integer, Vector> strEncoderPreprocessor = new EncoderTrainer<Integer, Vector>()
                     .withEncoderType(EncoderType.STRING_ENCODER)
                     .withEncodedFeature(1)
-                    .withEncodedFeature(6) // <--- Changed index here.
+                    .withEncodedFeature(6)
                     .fit(ignite,
                         dataCache,
                         vectorizer
@@ -106,8 +105,10 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                         imputingPreprocessor
                     );
 
-                Preprocessor<Integer, Vector> normalizationPreprocessor = new NormalizationTrainer<Integer, Vector>()
-                    .withP(1)
+                NormalizationTrainer<Integer, Vector> normalizationTrainer = new NormalizationTrainer<Integer, Vector>()
+                    .withP(1);
+
+                Preprocessor<Integer, Vector> normalizationPreprocessor = normalizationTrainer
                     .fit(
                         ignite,
                         dataCache,
@@ -122,24 +123,28 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                     = new CrossValidation<>();
 
                 ParamGrid paramGrid = new ParamGrid()
-                    .addHyperParam("maxDeep", new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0})
-                    .addHyperParam("minImpurityDecrease", new Double[] {0.0, 0.25, 0.5});
+                    .withParameterSearchStrategy(new EvolutionOptimizationStrategy())
+                    .addHyperParam("p", normalizationTrainer::withP, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0})
+                    .addHyperParam("maxDeep", trainerCV::withMaxDeep, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0})
+                    .addHyperParam("minImpurityDecrease", trainerCV::withMinImpurityDecrease, new Double[]{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0});
 
                 BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
                     .withNegativeClsLb(0.0)
                     .withPositiveClsLb(1.0)
                     .withMetric(BinaryClassificationMetricValues::accuracy);
 
-                CrossValidationResult crossValidationRes = scoreCalculator.score(
-                    trainerCV,
-                    metrics,
-                    ignite,
-                    dataCache,
-                    split.getTrainFilter(),
-                    normalizationPreprocessor,
-                    3,
-                    paramGrid
-                );
+                scoreCalculator
+                    .withIgnite(ignite)
+                    .withUpstreamCache(dataCache)
+                    .withTrainer(trainerCV)
+                    .withMetric(metrics)
+                    .withFilter(split.getTrainFilter())
+                    .isRunningOnPipeline(false)
+                    .withPreprocessor(normalizationPreprocessor)
+                    .withAmountOfFolds(3)
+                    .withParamGrid(paramGrid);
+
+                CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
 
                 System.out.println("Train with maxDeep: " + crossValidationRes.getBest("maxDeep")
                     + " and minImpurityDecrease: " + crossValidationRes.getBest("minImpurityDecrease"));
@@ -179,10 +184,11 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
-}
+}
\ No newline at end of file
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_14_Parallel_Genetic_Programming_Search.java
similarity index 79%
copy from examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
copy to examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_14_Parallel_Genetic_Programming_Search.java
index 7dcc104..dd43dac 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/Step_8_CV_with_Param_Grid_and_metrics.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/tutorial/hyperparametertuning/Step_14_Parallel_Genetic_Programming_Search.java
@@ -15,15 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.ml.tutorial;
+package org.apache.ignite.examples.ml.tutorial.hyperparametertuning;
 
 import java.io.FileNotFoundException;
 import java.util.Arrays;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
+import org.apache.ignite.examples.ml.tutorial.TitanicUtils;
 import org.apache.ignite.ml.dataset.feature.extractor.Vectorizer;
 import org.apache.ignite.ml.dataset.feature.extractor.impl.DummyVectorizer;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
+import org.apache.ignite.ml.environment.logging.ConsoleLogger;
+import org.apache.ignite.ml.environment.parallelism.ParallelismStrategy;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
 import org.apache.ignite.ml.preprocessing.Preprocessor;
 import org.apache.ignite.ml.preprocessing.encoding.EncoderTrainer;
@@ -33,6 +37,7 @@ import org.apache.ignite.ml.preprocessing.minmaxscaling.MinMaxScalerTrainer;
 import org.apache.ignite.ml.preprocessing.normalization.NormalizationTrainer;
 import org.apache.ignite.ml.selection.cv.CrossValidation;
 import org.apache.ignite.ml.selection.cv.CrossValidationResult;
+import org.apache.ignite.ml.selection.paramgrid.EvolutionOptimizationStrategy;
 import org.apache.ignite.ml.selection.paramgrid.ParamGrid;
 import org.apache.ignite.ml.selection.scoring.evaluator.Evaluator;
 import org.apache.ignite.ml.selection.scoring.metric.classification.Accuracy;
@@ -67,12 +72,9 @@ import org.apache.ignite.ml.tree.DecisionTreeNode;
  * <p>
  * All scenarios are described there: https://sebastianraschka.com/faq/docs/evaluate-a-model.html</p>
  */
-public class Step_8_CV_with_Param_Grid_and_metrics {
+public class Step_14_Parallel_Genetic_Programming_Search {
     /** Run example. */
     public static void main(String[] args) {
-        System.out.println();
-        System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-
         try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             try {
                 IgniteCache<Integer, Vector> dataCache = TitanicUtils.readPassengers(ignite);
@@ -87,7 +89,7 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 Preprocessor<Integer, Vector> strEncoderPreprocessor = new EncoderTrainer<Integer, Vector>()
                     .withEncoderType(EncoderType.STRING_ENCODER)
                     .withEncodedFeature(1)
-                    .withEncodedFeature(6) // <--- Changed index here.
+                    .withEncodedFeature(6)
                     .fit(ignite,
                         dataCache,
                         vectorizer
@@ -106,8 +108,10 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                         imputingPreprocessor
                     );
 
-                Preprocessor<Integer, Vector> normalizationPreprocessor = new NormalizationTrainer<Integer, Vector>()
-                    .withP(1)
+                NormalizationTrainer<Integer, Vector> normalizationTrainer = new NormalizationTrainer<Integer, Vector>()
+                    .withP(1);
+
+                Preprocessor<Integer, Vector> normalizationPreprocessor = normalizationTrainer
                     .fit(
                         ignite,
                         dataCache,
@@ -122,24 +126,31 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                     = new CrossValidation<>();
 
                 ParamGrid paramGrid = new ParamGrid()
-                    .addHyperParam("maxDeep", new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 10.0})
-                    .addHyperParam("minImpurityDecrease", new Double[] {0.0, 0.25, 0.5});
+                    .withParameterSearchStrategy(new EvolutionOptimizationStrategy())
+                    .addHyperParam("p", normalizationTrainer::withP, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0})
+                    .addHyperParam("maxDeep", trainerCV::withMaxDeep, new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0})
+                    .addHyperParam("minImpurityDecrease", trainerCV::withMinImpurityDecrease, new Double[]{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0});
 
                 BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
                     .withNegativeClsLb(0.0)
                     .withPositiveClsLb(1.0)
                     .withMetric(BinaryClassificationMetricValues::accuracy);
 
-                CrossValidationResult crossValidationRes = scoreCalculator.score(
-                    trainerCV,
-                    metrics,
-                    ignite,
-                    dataCache,
-                    split.getTrainFilter(),
-                    normalizationPreprocessor,
-                    3,
-                    paramGrid
-                );
+                scoreCalculator
+                    .withIgnite(ignite)
+                    .withUpstreamCache(dataCache)
+                    .withEnvironmentBuilder(LearningEnvironmentBuilder.defaultBuilder()
+                        .withParallelismStrategyTypeDependency(ParallelismStrategy.ON_DEFAULT_POOL)
+                        .withLoggingFactoryDependency(ConsoleLogger.Factory.LOW))
+                    .withTrainer(trainerCV)
+                    .withMetric(metrics)
+                    .withFilter(split.getTrainFilter())
+                    .isRunningOnPipeline(false)
+                    .withPreprocessor(normalizationPreprocessor)
+                    .withAmountOfFolds(3)
+                    .withParamGrid(paramGrid);
+
+                CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
 
                 System.out.println("Train with maxDeep: " + crossValidationRes.getBest("maxDeep")
                     + " and minImpurityDecrease: " + crossValidationRes.getBest("minImpurityDecrease"));
@@ -179,10 +190,11 @@ public class Step_8_CV_with_Param_Grid_and_metrics {
                 System.out.println("\n>>> Test Error " + (1 - accuracy));
 
                 System.out.println(">>> Tutorial step 8 (cross-validation with param grid) example started.");
-            }
-            catch (FileNotFoundException e) {
+            } catch (FileNotFoundException e) {
                 e.printStackTrace();
             }
+        } finally {
+            System.out.flush();
         }
     }
-}
+}
\ No newline at end of file
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/util/DatasetHelper.java b/examples/src/main/java/org/apache/ignite/examples/ml/util/DatasetHelper.java
index 96de9ad..c904c27 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/util/DatasetHelper.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/util/DatasetHelper.java
@@ -53,5 +53,7 @@ public class DatasetHelper {
         System.out.println("Correlation matrix ");
         for (double[] row : corr)
             System.out.println("\t" + Arrays.toString(row));
+
+        System.out.flush();
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/ParametricVectorGeneratorExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/ParametricVectorGeneratorExample.java
index 217bb36..fb35b8a 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/ParametricVectorGeneratorExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/ParametricVectorGeneratorExample.java
@@ -61,5 +61,6 @@ public class ParametricVectorGeneratorExample {
         ).asDataStream();
 
         Tracer.showClassificationDatasetHtml("Butterfly", butterfly, 2000, 0, 1, false);
+        System.out.flush();
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/StandardGeneratorsExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/StandardGeneratorsExample.java
index 65ff98c..621ebc4 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/StandardGeneratorsExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/StandardGeneratorsExample.java
@@ -71,5 +71,6 @@ public class StandardGeneratorsExample {
         RegressionDataStream regression = RegressionDataStream.twoDimensional(
             x -> Math.abs(x * x - 10), -10, 10);
         Tracer.showRegressionDatasetInHtml("|x^2 - 10|", regression, 1000, 0);
+        System.out.flush();
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/VectorGeneratorFamilyExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/VectorGeneratorFamilyExample.java
index 6bd5d30..ff71877 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/VectorGeneratorFamilyExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/VectorGeneratorFamilyExample.java
@@ -61,5 +61,6 @@ public class VectorGeneratorFamilyExample {
 
         Tracer.showClassificationDatasetHtml("Family of ring sectors [both families as two calsses]", family.asDataStream(),
             2000, 0, 1, true);
+        System.out.flush();
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/VectorGeneratorPrimitivesExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/VectorGeneratorPrimitivesExample.java
index cc2a7af..e1494cc 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/VectorGeneratorPrimitivesExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/util/generators/VectorGeneratorPrimitivesExample.java
@@ -93,5 +93,6 @@ public class VectorGeneratorPrimitivesExample {
             }).rotate(Math.PI / 2);
 
         Tracer.showClassificationDatasetHtml("Axe blade", axeBlade.asDataStream(), 1500, 0, 1, false);
+        System.out.flush();
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/ml/xgboost/XGBoostModelParserExample.java b/examples/src/main/java/org/apache/ignite/examples/ml/xgboost/XGBoostModelParserExample.java
index 5f75310..39162d9 100644
--- a/examples/src/main/java/org/apache/ignite/examples/ml/xgboost/XGBoostModelParserExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/ml/xgboost/XGBoostModelParserExample.java
@@ -95,6 +95,8 @@ public class XGBoostModelParserExample {
                     System.out.println("Expected: " + expPrediction + ", prediction: " + prediction);
                 }
             }
+        } finally {
+            System.out.flush();
         }
     }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/DefaultParallelismStrategy.java b/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/DefaultParallelismStrategy.java
index 66d2fdb..e787aea 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/DefaultParallelismStrategy.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/DefaultParallelismStrategy.java
@@ -20,6 +20,7 @@ package org.apache.ignite.ml.environment.parallelism;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -38,6 +39,11 @@ public class DefaultParallelismStrategy implements ParallelismStrategy {
         return new FutureWrapper<>(pool.submit(task::get));
     }
 
+    /** {@inheritDoc} */
+    @Override public int getParallelism() {
+        return ((ForkJoinPool) pool).getParallelism();
+    }
+
     /**
      * Wrapper for future class.
      *
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/NoParallelismStrategy.java b/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/NoParallelismStrategy.java
index 759e06a..ecbb4d7 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/NoParallelismStrategy.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/NoParallelismStrategy.java
@@ -36,6 +36,11 @@ public class NoParallelismStrategy implements ParallelismStrategy {
     }
 
     /** {@inheritDoc} */
+    @Override public int getParallelism() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
     @Override public <T>  Promise<T> submit(IgniteSupplier<T> task) {
         return new Stub<>(task.get());
     }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/ParallelismStrategy.java b/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/ParallelismStrategy.java
index f27281f..11d5f55 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/ParallelismStrategy.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/environment/parallelism/ParallelismStrategy.java
@@ -17,11 +17,10 @@
 
 package org.apache.ignite.ml.environment.parallelism;
 
-import org.apache.ignite.ml.math.functions.IgniteFunction;
-import org.apache.ignite.ml.math.functions.IgniteSupplier;
-
 import java.util.ArrayList;
 import java.util.List;
+import org.apache.ignite.ml.math.functions.IgniteFunction;
+import org.apache.ignite.ml.math.functions.IgniteSupplier;
 
 /**
  * Specifies the behaviour of processes in ML-algorithms that can may be parallelized such as parallel learning in
@@ -40,15 +39,20 @@ public interface ParallelismStrategy {
      * Submit task.
      *
      * @param task Task.
+     *
+     * @return The result of submit operation.
      */
     public <T> Promise<T> submit(IgniteSupplier<T> task);
 
+    /** Returns default parallelism. */
+    public int getParallelism();
+
     /**
      * Submit the list of tasks.
      *
      * @param tasks The task list.
      * @param <T> The type of return value.
-     * @return The result of submit operation.
+     * @return The results of the submitted operations list.
      */
     public default <T> List<Promise<T>> submit(List<IgniteSupplier<T>> tasks) {
         List<Promise<T>> results = new ArrayList<>();
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainer.java
index a6493f7..b1e50d4 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/preprocessing/normalization/NormalizationTrainer.java
@@ -54,9 +54,9 @@ public class NormalizationTrainer<K, V> implements PreprocessingTrainer<K, V> {
      * @param p The given value.
      * @return The Normalization trainer.
      */
-    public NormalizationTrainer<K, V> withP(int p) {
+    public NormalizationTrainer<K, V> withP(double p) {
         assert p > 0;
-        this.p = p;
+        this.p = (int) p;
         return this;
     }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainer.java
index 9358aeb..63dfb95 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/regressions/logistic/LogisticRegressionSGDTrainer.java
@@ -158,8 +158,8 @@ public class LogisticRegressionSGDTrainer extends SingleLabelDatasetTrainer<Logi
      * @param maxIterations The parameter value.
      * @return Model with new max number of iterations before convergence parameter value.
      */
-    public LogisticRegressionSGDTrainer withMaxIterations(int maxIterations) {
-        this.maxIterations = maxIterations;
+    public LogisticRegressionSGDTrainer withMaxIterations(double maxIterations) {
+        this.maxIterations = (int) maxIterations;
         return this;
     }
 
@@ -169,8 +169,8 @@ public class LogisticRegressionSGDTrainer extends SingleLabelDatasetTrainer<Logi
      * @param batchSize The size of learning batch.
      * @return Trainer with new batch size parameter value.
      */
-    public LogisticRegressionSGDTrainer withBatchSize(int batchSize) {
-        this.batchSize = batchSize;
+    public LogisticRegressionSGDTrainer withBatchSize(double batchSize) {
+        this.batchSize = (int) batchSize;
         return this;
     }
 
@@ -180,8 +180,8 @@ public class LogisticRegressionSGDTrainer extends SingleLabelDatasetTrainer<Logi
      * @param amountOfLocIterations The parameter value.
      * @return Trainer with new locIterations parameter value.
      */
-    public LogisticRegressionSGDTrainer withLocIterations(int amountOfLocIterations) {
-        this.locIterations = amountOfLocIterations;
+    public LogisticRegressionSGDTrainer withLocIterations(double amountOfLocIterations) {
+        this.locIterations = (int) amountOfLocIterations;
         return this;
     }
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/AbstractCrossValidation.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/AbstractCrossValidation.java
new file mode 100644
index 0000000..be676f7
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/AbstractCrossValidation.java
@@ -0,0 +1,476 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ml.selection.cv;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.function.BiFunction;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.ignite.lang.IgniteBiPredicate;
+import org.apache.ignite.ml.IgniteModel;
+import org.apache.ignite.ml.dataset.DatasetBuilder;
+import org.apache.ignite.ml.environment.LearningEnvironment;
+import org.apache.ignite.ml.environment.LearningEnvironmentBuilder;
+import org.apache.ignite.ml.environment.parallelism.Promise;
+import org.apache.ignite.ml.math.functions.IgniteSupplier;
+import org.apache.ignite.ml.math.primitives.vector.Vector;
+import org.apache.ignite.ml.pipeline.Pipeline;
+import org.apache.ignite.ml.pipeline.PipelineMdl;
+import org.apache.ignite.ml.preprocessing.Preprocessor;
+import org.apache.ignite.ml.selection.paramgrid.BruteForceStrategy;
+import org.apache.ignite.ml.selection.paramgrid.EvolutionOptimizationStrategy;
+import org.apache.ignite.ml.selection.paramgrid.HyperParameterTuningStrategy;
+import org.apache.ignite.ml.selection.paramgrid.ParamGrid;
+import org.apache.ignite.ml.selection.paramgrid.ParameterSetGenerator;
+import org.apache.ignite.ml.selection.paramgrid.RandomStrategy;
+import org.apache.ignite.ml.selection.scoring.cursor.LabelPairCursor;
+import org.apache.ignite.ml.selection.scoring.metric.Metric;
+import org.apache.ignite.ml.selection.split.mapper.SHA256UniformMapper;
+import org.apache.ignite.ml.selection.split.mapper.UniformMapper;
+import org.apache.ignite.ml.trainers.DatasetTrainer;
+import org.apache.ignite.ml.util.genetic.Chromosome;
+import org.apache.ignite.ml.util.genetic.GeneticAlgorithm;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Cross validation score calculator. Cross validation is an approach that allows to avoid overfitting that is made the
+ * following way: the training set is split into k smaller sets. The following procedure is followed for each of the k
+ * “folds”:
+ * <ul>
+ * <li>A model is trained using k-1 of the folds as training data;</li>
+ * <li>the resulting model is validated on the remaining part of the data (i.e., it is used as a test set to compute
+ * a performance measure such as accuracy).</li>
+ * </ul>
+ *
+ * @param <M> Type of model.
+ * @param <L> Type of a label (truth or prediction).
+ * @param <K> Type of a key in {@code upstream} data.
+ * @param <V> Type of a value in {@code upstream} data.
+ */
+public abstract class AbstractCrossValidation<M extends IgniteModel<Vector, L>, L, K, V> {
+    /** Learning environment builder. */
+    protected LearningEnvironmentBuilder envBuilder = LearningEnvironmentBuilder.defaultBuilder();
+
+    /** Learning Environment. */
+    protected LearningEnvironment environment = envBuilder.buildForTrainer();
+
+    /** Trainer. */
+    protected DatasetTrainer<M, L> trainer;
+
+    /** Pipeline. */
+    protected Pipeline<K, V, Integer, Double> pipeline;
+
+    /** Metric. */
+    protected Metric<L> metric;
+
+    /** Preprocessor. */
+    protected Preprocessor<K, V> preprocessor;
+
+    /** Filter. */
+    protected IgniteBiPredicate<K, V> filter = (k, v) -> true;
+
+    /** Amount of folds. */
+    protected int amountOfFolds;
+
+    /** Parts. */
+    protected int parts;
+
+    /** Parameter grid. */
+    protected ParamGrid paramGrid;
+
+    /** Execution over the pipeline or the chain of preprocessors and separate trainer, otherwise. */
+    protected boolean isRunningOnPipeline = true;
+
+    /** Mapper. */
+    protected UniformMapper<K, V> mapper = new SHA256UniformMapper<>();
+
+    /**
+     * Finds the best set of hyperparameters based on parameter search strategy.
+     */
+    public CrossValidationResult tuneHyperParamterers() {
+        HyperParameterTuningStrategy hyperParamTuningStgy = paramGrid.getHyperParameterTuningStrategy();
+
+        if (hyperParamTuningStgy instanceof BruteForceStrategy) return scoreBruteForceHyperparameterOptimization();
+        if (hyperParamTuningStgy instanceof RandomStrategy) return scoreRandomSearchHyperparameterOptimization();
+        if (hyperParamTuningStgy instanceof EvolutionOptimizationStrategy)
+            return scoreEvolutionAlgorithmSearchHyperparameterOptimization();
+        else throw new UnsupportedOperationException("This strategy is not supported yet [strategy="
+            + paramGrid.getHyperParameterTuningStrategy().getName() + "]");
+    }
+
+    /**
+     * Finds the best set of hyperparameters based on Genetic Programming approach.
+     */
+    private CrossValidationResult scoreEvolutionAlgorithmSearchHyperparameterOptimization() {
+        EvolutionOptimizationStrategy stgy = (EvolutionOptimizationStrategy) paramGrid.getHyperParameterTuningStrategy();
+
+        List<Double[]> paramSets = new ParameterSetGenerator(paramGrid.getParamValuesByParamIdx()).generate();
+
+        // initialization
+        List<Double[]> paramSetsCp = new ArrayList<>(paramSets);
+        Collections.shuffle(paramSetsCp, new Random(stgy.getSeed()));
+
+        int sizeOfPopulation = 20;
+        List<Double[]> rndParamSets = paramSetsCp.subList(0, sizeOfPopulation);
+
+        CrossValidationResult cvRes = new CrossValidationResult();
+
+        Function<Chromosome, Double> fitnessFunction = (Chromosome chromosome) -> {
+            TaskResult tr = calculateScoresForFixedParamSet(chromosome.toDoubleArray());
+
+            cvRes.addScores(tr.locScores, tr.paramMap);
+
+            final double locAvgScore = Arrays.stream(tr.locScores).average().orElse(Double.MIN_VALUE);
+
+            if (locAvgScore >= cvRes.getBestAvgScore()) {
+                cvRes.setBestScore(tr.locScores);
+                cvRes.setBestHyperParams(tr.paramMap);
+            }
+
+            return locAvgScore;
+        };
+
+        Random rnd = new Random(stgy.getSeed()); //TODO: common seed for shared lambdas can produce the same value on each function call? or sequent?
+
+        BiFunction<Integer, Double, Double> mutator = (Integer geneIdx, Double geneValue) -> {
+            Double newGeneVal;
+
+            Double[] possibleGeneValues = paramGrid.getParamRawData().get(geneIdx);
+            newGeneVal = possibleGeneValues[rnd.nextInt(possibleGeneValues.length)];
+
+            return newGeneVal;
+        };
+
+        GeneticAlgorithm ga = new GeneticAlgorithm(rndParamSets);
+        ga.withFitnessFunction(fitnessFunction)
+            .withMutationOperator(mutator)
+            .withAmountOfEliteChromosomes(stgy.getAmountOfEliteChromosomes())
+            .withCrossingoverProbability(stgy.getCrossingoverProbability())
+            .withCrossoverStgy(stgy.getCrossoverStgy())
+            .withAmountOfGenerations(stgy.getAmountOfGenerations())
+            .withSelectionStgy(stgy.getSelectionStgy())
+            .withMutationProbability(stgy.getMutationProbability());
+
+        if (environment.parallelismStrategy().getParallelism() > 1)
+            ga.runParallel(environment);
+        else
+            ga.run();
+
+        return cvRes;
+    }
+
+    /**
+     * Finds the best set of hyperparameters based on Random Serach.
+     */
+    private CrossValidationResult scoreRandomSearchHyperparameterOptimization() {
+        RandomStrategy stgy = (RandomStrategy) paramGrid.getHyperParameterTuningStrategy();
+
+        List<Double[]> paramSets = new ParameterSetGenerator(paramGrid.getParamValuesByParamIdx()).generate();
+
+        List<Double[]> paramSetsCp = new ArrayList<>(paramSets);
+        Collections.shuffle(paramSetsCp, new Random(stgy.getSeed()));
+
+        CrossValidationResult cvRes = new CrossValidationResult();
+
+        List<Double[]> rndParamSets = paramSetsCp.subList(0, stgy.getMaxTries());
+
+        List<IgniteSupplier<TaskResult>> tasks = rndParamSets.stream()
+            .map(paramSet -> (IgniteSupplier<TaskResult>) (() -> calculateScoresForFixedParamSet(paramSet)))
+            .collect(Collectors.toList());
+
+        List<TaskResult> taskResults = environment.parallelismStrategy().submit(tasks).stream()
+            .map(Promise::unsafeGet)
+            .collect(Collectors.toList());
+
+        taskResults.forEach(tr -> {
+            cvRes.addScores(tr.locScores, tr.paramMap);
+
+            final double locAvgScore = Arrays.stream(tr.locScores).average().orElse(Double.MIN_VALUE);
+
+            if (locAvgScore >= cvRes.getBestAvgScore()) {
+                cvRes.setBestScore(tr.locScores);
+                cvRes.setBestHyperParams(tr.paramMap);
+            }
+        });
+
+        return cvRes;
+    }
+
+    /**
+     * Finds the best set of hyperparameters based on brute force approach .
+     */
+    private CrossValidationResult scoreBruteForceHyperparameterOptimization() {
+        List<Double[]> paramSets = new ParameterSetGenerator(paramGrid.getParamValuesByParamIdx()).generate();
+
+        CrossValidationResult cvRes = new CrossValidationResult();
+
+        List<IgniteSupplier<TaskResult>> tasks = paramSets.stream()
+            .map(paramSet -> (IgniteSupplier<TaskResult>) (() -> calculateScoresForFixedParamSet(paramSet)))
+            .collect(Collectors.toList());
+
+        List<TaskResult> taskResults = environment.parallelismStrategy().submit(tasks).stream()
+            .map(Promise::unsafeGet)
+            .collect(Collectors.toList());
+
+        taskResults.forEach(tr -> {
+            cvRes.addScores(tr.locScores, tr.paramMap);
+
+            final double locAvgScore = Arrays.stream(tr.locScores).average().orElse(Double.MIN_VALUE);
+
+            if (locAvgScore > cvRes.getBestAvgScore()) {
+                cvRes.setBestScore(tr.locScores);
+                cvRes.setBestHyperParams(tr.paramMap);
+            }
+
+        });
+        return cvRes;
+    }
+
+    /**
+     * Represents the scores and map of parameters.
+     */
+    public static class TaskResult {
+        /** Parameter map. */
+        private Map<String, Double> paramMap;
+
+        /** Local scores. */
+        private double[] locScores;
+
+        /**
+         * @param paramMap  Parameter map.
+         * @param locScores Locale scores.
+         */
+        public TaskResult(Map<String, Double> paramMap, double[] locScores) {
+            this.paramMap = paramMap;
+            this.locScores = locScores;
+        }
+
+        /**
+         * @param paramMap Parameter map.
+         */
+        public void setParamMap(Map<String, Double> paramMap) {
+            this.paramMap = paramMap;
+        }
+
+        /**
+         * @param locScores Local scores.
+         */
+        public void setLocScores(double[] locScores) {
+            this.locScores = locScores;
+        }
+    }
+
+    /**
+     * Calculates scores by folds and wrap it to TaskResult object.
+     *
+     * @param paramSet Parameter set.
+     */
+    private TaskResult calculateScoresForFixedParamSet(Double[] paramSet) {
+        Map<String, Double> paramMap = injectAndGetParametersFromPipeline(paramGrid, paramSet);
+
+        double[] locScores = scoreByFolds();
+
+        return new TaskResult(paramMap, locScores);
+    }
+
+    /**
+     * Calculates score by folds.
+     */
+    public abstract double[] scoreByFolds();
+
+    /**
+     * Forms the parameter map from parameter grid and parameter set.
+     *
+     * @param paramGrid Parameter grid.
+     * @param paramSet  Parameter set.
+     */
+    @NotNull private Map<String, Double> injectAndGetParametersFromPipeline(ParamGrid paramGrid, Double[] paramSet) {
+        Map<String, Double> paramMap = new HashMap<>();
+
+        for (int paramIdx = 0; paramIdx < paramSet.length; paramIdx++) {
+            DoubleConsumer setter = paramGrid.getSetterByIndex(paramIdx);
+
+            Double paramVal = paramSet[paramIdx];
+            setter.accept(paramVal);
+
+            paramMap.put(paramGrid.getParamNameByIndex(paramIdx), paramVal);
+
+        }
+        return paramMap;
+    }
+
+    /**
+     * Computes cross-validated metrics.
+     *
+     * @param datasetBuilderSupplier Dataset builder supplier.
+     * @param testDataIterSupplier   Test data iterator supplier.
+     * @return Array of scores of the estimator for each run of the cross validation.
+     */
+    protected double[] score(Function<IgniteBiPredicate<K, V>, DatasetBuilder<K, V>> datasetBuilderSupplier,
+                             BiFunction<IgniteBiPredicate<K, V>, M, LabelPairCursor<L>> testDataIterSupplier) {
+        double[] scores = new double[amountOfFolds];
+
+        double foldSize = 1.0 / amountOfFolds;
+        for (int i = 0; i < amountOfFolds; i++) {
+            double from = foldSize * i;
+            double to = foldSize * (i + 1);
+
+            IgniteBiPredicate<K, V> trainSetFilter = (k, v) -> {
+                double pnt = mapper.map(k, v);
+                return pnt < from || pnt > to;
+            };
+
+            DatasetBuilder<K, V> datasetBuilder = datasetBuilderSupplier.apply(trainSetFilter);
+            M mdl = trainer.fit(datasetBuilder, preprocessor); //TODO: IGNITE-11580
+
+            try (LabelPairCursor<L> cursor = testDataIterSupplier.apply(trainSetFilter, mdl)) {
+                scores[i] = metric.score(cursor.iterator());
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        return scores;
+    }
+
+    /**
+     * Computes cross-validated metrics.
+     *
+     * @param datasetBuilderSupplier Dataset builder supplier.
+     * @param testDataIterSupplier   Test data iterator supplier.
+     * @return Array of scores of the estimator for each run of the cross validation.
+     */
+    protected double[] scorePipeline(Function<IgniteBiPredicate<K, V>, DatasetBuilder<K, V>> datasetBuilderSupplier,
+                                     BiFunction<IgniteBiPredicate<K, V>, M, LabelPairCursor<L>> testDataIterSupplier) {
+        double[] scores = new double[amountOfFolds];
+
+        double foldSize = 1.0 / amountOfFolds;
+        for (int i = 0; i < amountOfFolds; i++) {
+            double from = foldSize * i;
+            double to = foldSize * (i + 1);
+
+            IgniteBiPredicate<K, V> trainSetFilter = (k, v) -> {
+                double pnt = mapper.map(k, v);
+                return pnt < from || pnt > to;
+            };
+
+            DatasetBuilder<K, V> datasetBuilder = datasetBuilderSupplier.apply(trainSetFilter);
+            PipelineMdl<K, V> mdl = pipeline.fit(datasetBuilder);
+
+            try (LabelPairCursor<L> cursor = testDataIterSupplier.apply(trainSetFilter, (M) mdl)) {
+                scores[i] = metric.score(cursor.iterator());
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        return scores;
+    }
+
+    /**
+     * @param trainer Trainer.
+     */
+    public AbstractCrossValidation<M, L, K, V> withTrainer(DatasetTrainer<M, L> trainer) {
+        this.trainer = trainer;
+        return this;
+    }
+
+    /**
+     * @param metric Metric.
+     */
+    public AbstractCrossValidation<M, L, K, V> withMetric(Metric<L> metric) {
+        this.metric = metric;
+        return this;
+    }
+
+    /**
+     * @param preprocessor Preprocessor.
+     */
+    public AbstractCrossValidation<M, L, K, V> withPreprocessor(Preprocessor<K, V> preprocessor) {
+        this.preprocessor = preprocessor;
+        return this;
+    }
+
+    /**
+     * @param filter Filter.
+     */
+    public AbstractCrossValidation<M, L, K, V> withFilter(IgniteBiPredicate<K, V> filter) {
+        this.filter = filter;
+        return this;
+    }
+
+    /**
+     * @param amountOfFolds Amount of folds.
+     */
+    public AbstractCrossValidation<M, L, K, V> withAmountOfFolds(int amountOfFolds) {
+        this.amountOfFolds = amountOfFolds;
+        return this;
+    }
+
+    /**
+     * @param paramGrid Parameter grid.
+     */
+    public AbstractCrossValidation<M, L, K, V> withParamGrid(ParamGrid paramGrid) {
+        this.paramGrid = paramGrid;
+        return this;
+    }
+
+    /**
+     * @param runningOnPipeline Running on pipeline.
+     */
+    public AbstractCrossValidation<M, L, K, V> isRunningOnPipeline(boolean runningOnPipeline) {
+        isRunningOnPipeline = runningOnPipeline;
+        return this;
+    }
+
+    /**
+     * Changes learning Environment.
+     *
+     * @param envBuilder Learning environment builder.
+     */
+    // TODO: IGNITE-10441 Think about more elegant ways to perform fluent API.
+    public AbstractCrossValidation<M, L, K, V> withEnvironmentBuilder(LearningEnvironmentBuilder envBuilder) {
+        this.envBuilder = envBuilder;
+        environment = envBuilder.buildForTrainer();
+
+        return this;
+    }
+
+    /**
+     * @param pipeline Pipeline.
+     */
+    public AbstractCrossValidation<M, L, K, V> withPipeline(Pipeline<K, V, Integer, Double> pipeline) {
+        this.pipeline = pipeline;
+        return this;
+    }
+
+    /**
+     * @param mapper Mapper.
+     */
+    public AbstractCrossValidation<M, L, K, V> withMapper(UniformMapper<K, V> mapper) {
+        this.mapper = mapper;
+        return this;
+    }
+}
\ No newline at end of file
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/CrossValidation.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/CrossValidation.java
index b3c70e5..159285b 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/CrossValidation.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/CrossValidation.java
@@ -17,42 +17,21 @@
 
 package org.apache.ignite.ml.selection.cv;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.BiFunction;
-import java.util.function.Function;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
-import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.ml.IgniteModel;
-import org.apache.ignite.ml.dataset.DatasetBuilder;
 import org.apache.ignite.ml.dataset.impl.cache.CacheBasedDatasetBuilder;
-import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
 import org.apache.ignite.ml.math.primitives.vector.Vector;
-import org.apache.ignite.ml.pipeline.Pipeline;
 import org.apache.ignite.ml.pipeline.PipelineMdl;
-import org.apache.ignite.ml.preprocessing.Preprocessor;
-import org.apache.ignite.ml.selection.paramgrid.ParamGrid;
-import org.apache.ignite.ml.selection.paramgrid.ParameterSetGenerator;
 import org.apache.ignite.ml.selection.scoring.cursor.CacheBasedLabelPairCursor;
-import org.apache.ignite.ml.selection.scoring.cursor.LabelPairCursor;
-import org.apache.ignite.ml.selection.scoring.cursor.LocalLabelPairCursor;
-import org.apache.ignite.ml.selection.scoring.metric.Metric;
-import org.apache.ignite.ml.selection.split.mapper.SHA256UniformMapper;
-import org.apache.ignite.ml.selection.split.mapper.UniformMapper;
-import org.apache.ignite.ml.trainers.DatasetTrainer;
 
 /**
  * Cross validation score calculator. Cross validation is an approach that allows to avoid overfitting that is made the
  * following way: the training set is split into k smaller sets. The following procedure is followed for each of the k
  * “folds”:
  * <ul>
- *    <li>A model is trained using k-1 of the folds as training data;</li>
- *    <li>the resulting model is validated on the remaining part of the data (i.e., it is used as a test set to compute
+ * <li>A model is trained using k-1 of the folds as training data;</li>
+ * <li>the resulting model is validated on the remaining part of the data (i.e., it is used as a test set to compute
  * a performance measure such as accuracy).</li>
  * </ul>
  *
@@ -61,136 +40,31 @@ import org.apache.ignite.ml.trainers.DatasetTrainer;
  * @param <K> Type of a key in {@code upstream} data.
  * @param <V> Type of a value in {@code upstream} data.
  */
-public class CrossValidation<M extends IgniteModel<Vector, L>, L, K, V> {
-    /**
-     * Computes cross-validated metrics.
-     *
-     * @param trainer          Trainer of the model.
-     * @param scoreCalculator  Score calculator.
-     * @param ignite           Ignite instance.
-     * @param upstreamCache    Ignite cache with {@code upstream} data.
-     * @param preprocessor      Preprocessor.
-     * @param cv               Number of folds.
-     * @return Array of scores of the estimator for each run of the cross validation.
-     */
-    public double[] score(DatasetTrainer<M, L> trainer, Metric<L> scoreCalculator, Ignite ignite,
-                          IgniteCache<K, V> upstreamCache, Preprocessor<K, V> preprocessor, int cv) {
-        return score(trainer, scoreCalculator, ignite, upstreamCache, (k, v) -> true, preprocessor,
-            new SHA256UniformMapper<>(), cv);
-    }
+public class CrossValidation<M extends IgniteModel<Vector, L>, L, K, V> extends AbstractCrossValidation<M, L, K, V> {
+    /** Ignite. */
+    private Ignite ignite;
 
-    /**
-     * Computes cross-validated metrics.
-     *
-     * @param trainer          Trainer of the model.
-     * @param scoreCalculator  Base score calculator.
-     * @param ignite           Ignite instance.
-     * @param upstreamCache    Ignite cache with {@code upstream} data.
-     * @param filter           Base {@code upstream} data filter.
-     * @param preprocessor      Preprocessor.
-     * @param cv               Number of folds.
-     * @return Array of scores of the estimator for each run of the cross validation.
-     */
-    public double[] score(DatasetTrainer<M, L> trainer, Metric<L> scoreCalculator, Ignite ignite,
-                          IgniteCache<K, V> upstreamCache, IgniteBiPredicate<K, V> filter,
-                          Preprocessor<K, V> preprocessor, int cv) {
-        return score(trainer, scoreCalculator, ignite, upstreamCache, filter, preprocessor,
-            new SHA256UniformMapper<>(), cv);
-    }
+    /** Upstream cache. */
+    private IgniteCache<K, V> upstreamCache;
 
     /**
-     * Computes cross-validated metrics with a passed parameter grid.
-     *
-     * The real cross-validation training will be called each time for each parameter set.
-     *
-     * @param trainer          Trainer of the model.
-     * @param scoreCalculator  Base score calculator.
-     * @param ignite           Ignite instance.
-     * @param upstreamCache    Ignite cache with {@code upstream} data.
-     * @param filter           Base {@code upstream} data filter.
-     * @param preprocessor      Preprocessor.
-     * @param amountOfFolds    Amount of folds.
-     * @param paramGrid        Parameter grid.
-     * @return Array of scores of the estimator for each run of the cross validation.
+     * Calculates score by folds.
      */
-    public CrossValidationResult score(DatasetTrainer<M, L> trainer, Metric<L> scoreCalculator, Ignite ignite,
-                                       IgniteCache<K, V> upstreamCache, IgniteBiPredicate<K, V> filter,
-                                       Preprocessor<K, V> preprocessor, int amountOfFolds,
-                                       ParamGrid paramGrid) {
-
-        List<Double[]> paramSets = new ParameterSetGenerator(paramGrid.getParamValuesByParamIdx()).generate();
-
-        CrossValidationResult cvRes = new CrossValidationResult();
-
-        paramSets.forEach(paramSet -> {
-            Map<String, Double> paramMap = new HashMap<>();
-
-            for (int paramIdx = 0; paramIdx < paramSet.length; paramIdx++) {
-                String paramName = paramGrid.getParamNameByIndex(paramIdx);
-                Double paramVal = paramSet[paramIdx];
-
-                paramMap.put(paramName, paramVal);
-
-                try {
-                    final String mtdName = "with" +
-                        paramName.substring(0, 1).toUpperCase() +
-                        paramName.substring(1);
-
-                    Method trainerSetter = null;
-
-                    // We should iterate along all methods due to we have no info about signature and passed types.
-                    for (Method method : trainer.getClass().getDeclaredMethods()) {
-                        if (method.getName().equals(mtdName))
-                            trainerSetter = method;
-                    }
-
-                    if (trainerSetter != null)
-                        trainerSetter.invoke(trainer, paramVal);
-                    else
-                        throw new NoSuchMethodException(mtdName);
+    @Override public double[] scoreByFolds() {
+        double[] locScores;
 
-                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
-                    e.printStackTrace();
-                }
-            }
+        locScores = isRunningOnPipeline ? scorePipelineOnIgnite() : scoreOnIgnite();
 
-            double[] locScores = score(trainer, scoreCalculator, ignite, upstreamCache, filter, preprocessor,
-                new SHA256UniformMapper<>(), amountOfFolds);
-
-            cvRes.addScores(locScores, paramMap);
-
-            final double locAvgScore = Arrays.stream(locScores).average().orElse(Double.MIN_VALUE);
-
-            if (locAvgScore > cvRes.getBestAvgScore()) {
-                cvRes.setBestScore(locScores);
-                cvRes.setBestHyperParams(paramMap);
-                System.out.println(paramMap.toString());
-            }
-        });
-
-        return cvRes;
+        return locScores;
     }
 
     /**
-     * Computes cross-validated metrics.
+     * Calculate score on pipeline based on Ignite data (upstream cache).
      *
-     * @param trainer          Trainer of the model.
-     * @param scoreCalculator  Base score calculator.
-     * @param ignite           Ignite instance.
-     * @param upstreamCache    Ignite cache with {@code upstream} data.
-     * @param filter           Base {@code upstream} data filter.
-     * @param preprocessor      Preprocessor.
-     * @param mapper           Mapper used to map a key-value pair to a point on the segment (0, 1).
-     * @param cv               Number of folds.
      * @return Array of scores of the estimator for each run of the cross validation.
      */
-    public double[] score(DatasetTrainer<M, L> trainer, Metric<L> scoreCalculator,
-                          Ignite ignite, IgniteCache<K, V> upstreamCache, IgniteBiPredicate<K, V> filter,
-                          Preprocessor<K, V> preprocessor,
-                          UniformMapper<K, V> mapper, int cv) {
-
-        return score(
-            trainer,
+    private double[] scorePipelineOnIgnite() {
+        return scorePipeline(
             predicate -> new CacheBasedDatasetBuilder<>(
                 ignite,
                 upstreamCache,
@@ -199,262 +73,46 @@ public class CrossValidation<M extends IgniteModel<Vector, L>, L, K, V> {
             (predicate, mdl) -> new CacheBasedLabelPairCursor<>(
                 upstreamCache,
                 (k, v) -> filter.apply(k, v) && !predicate.apply(k, v),
-                preprocessor,
+                ((PipelineMdl<K, V>) mdl).getPreprocessor(),
                 mdl
-            ),
-            preprocessor,
-            scoreCalculator,
-            mapper,
-            cv
+            )
         );
     }
 
     /**
      * Computes cross-validated metrics.
      *
-     * @param trainer          Trainer of the model.
-     * @param scoreCalculator  Base score calculator.
-     * @param upstreamMap      Map with {@code upstream} data.
-     * @param parts            Number of partitions.
-     * @param preprocessor      Preprocessor.
-     * @param cv               Number of folds.
-     * @return Array of scores of the estimator for each run of the cross validation.
-     */
-    public double[] score(DatasetTrainer<M, L> trainer, Metric<L> scoreCalculator, Map<K, V> upstreamMap,
-                          int parts, Preprocessor<K, V> preprocessor, int cv) {
-        return score(trainer, scoreCalculator, upstreamMap, (k, v) -> true, parts, preprocessor,
-            new SHA256UniformMapper<>(), cv);
-    }
-
-    /**
-     * Computes cross-validated metrics.
-     *
-     * @param trainer          Trainer of the model.
-     * @param scoreCalculator  Base score calculator.
-     * @param upstreamMap      Map with {@code upstream} data.
-     * @param filter           Base {@code upstream} data filter.
-     * @param parts            Number of partitions.
-     * @param preprocessor      Preprocessor.
-     * @param cv               Number of folds.
-     * @return Array of scores of the estimator for each run of the cross validation.
-     */
-    public double[] score(DatasetTrainer<M, L> trainer, Metric<L> scoreCalculator, Map<K, V> upstreamMap,
-                          IgniteBiPredicate<K, V> filter, int parts, Preprocessor<K, V> preprocessor, int cv) {
-        return score(trainer, scoreCalculator, upstreamMap, filter, parts, preprocessor,
-            new SHA256UniformMapper<>(), cv);
-    }
-
-    /**
-     * Computes cross-validated metrics.
-     *
-     * @param trainer          Trainer of the model.
-     * @param scoreCalculator  Base score calculator.
-     * @param upstreamMap      Map with {@code upstream} data.
-     * @param filter           Base {@code upstream} data filter.
-     * @param parts            Number of partitions.
-     * @param preprocessor      Preprocessor.
-     * @param mapper           Mapper used to map a key-value pair to a point on the segment (0, 1).
-     * @param cv               Number of folds.
      * @return Array of scores of the estimator for each run of the cross validation.
      */
-    public double[] score(DatasetTrainer<M, L> trainer, Metric<L> scoreCalculator, Map<K, V> upstreamMap,
-                          IgniteBiPredicate<K, V> filter, int parts, Preprocessor<K, V> preprocessor, UniformMapper<K, V> mapper, int cv) {
+    private double[] scoreOnIgnite() {
         return score(
-            trainer,
-            predicate -> new LocalDatasetBuilder<>(
-                upstreamMap,
-                (k, v) -> filter.apply(k, v) && predicate.apply(k, v),
-                parts
+            predicate -> new CacheBasedDatasetBuilder<>(
+                ignite,
+                upstreamCache,
+                (k, v) -> filter.apply(k, v) && predicate.apply(k, v)
             ),
-            (predicate, mdl) -> new LocalLabelPairCursor<>(
-                upstreamMap,
+            (predicate, mdl) -> new CacheBasedLabelPairCursor<>(
+                upstreamCache,
                 (k, v) -> filter.apply(k, v) && !predicate.apply(k, v),
                 preprocessor,
                 mdl
-            ),
-            preprocessor,
-            scoreCalculator,
-            mapper,
-            cv
+            )
         );
     }
 
     /**
-     * Computes cross-validated metrics.
-     *
-     * @param trainer                Trainer of the model.
-     * @param datasetBuilderSupplier Dataset builder supplier.
-     * @param testDataIterSupplier   Test data iterator supplier.
-     * @param scoreCalculator        Base score calculator.
-     * @param mapper                 Mapper used to map a key-value pair to a point on the segment (0, 1).
-     * @param cv                     Number of folds.
-     * @return Array of scores of the estimator for each run of the cross validation.
-     */
-    private double[] score(DatasetTrainer<M, L> trainer, Function<IgniteBiPredicate<K, V>,
-        DatasetBuilder<K, V>> datasetBuilderSupplier,
-                           BiFunction<IgniteBiPredicate<K, V>, M, LabelPairCursor<L>> testDataIterSupplier,
-                           Preprocessor<K, V> preprocessor,
-                           Metric<L> scoreCalculator, UniformMapper<K, V> mapper, int cv) {
-
-        double[] scores = new double[cv];
-
-        double foldSize = 1.0 / cv;
-        for (int i = 0; i < cv; i++) {
-            double from = foldSize * i;
-            double to = foldSize * (i + 1);
-
-            IgniteBiPredicate<K, V> trainSetFilter = (k, v) -> {
-                double pnt = mapper.map(k, v);
-                return pnt < from || pnt > to;
-            };
-
-            DatasetBuilder<K, V> datasetBuilder = datasetBuilderSupplier.apply(trainSetFilter);
-            M mdl = trainer.fit(datasetBuilder, preprocessor); //TODO: IGNITE-11580
-
-            try (LabelPairCursor<L> cursor = testDataIterSupplier.apply(trainSetFilter, mdl)) {
-                scores[i] = scoreCalculator.score(cursor.iterator());
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        return scores;
-    }
-
-    /**
-     * Computes cross-validated metrics with a passed parameter grid.
-     *
-     * The real cross-validation training will be called each time for each parameter set.
-     *
-     * @param pipeline        Pipeline of stages.
-     * @param scoreCalculator Base score calculator.
-     * @param ignite          Ignite instance.
-     * @param upstreamCache   Ignite cache with {@code upstream} data.
-     * @param filter          Base {@code upstream} data filter.
-     * @param amountOfFolds   Amount of folds.
-     * @param paramGrid       Parameter grid.
-     * @return Array of scores of the estimator for each run of the cross validation.
+     * @param ignite Ignite.
      */
-    public CrossValidationResult score(Pipeline<K, V, Integer, Double> pipeline,
-                                       Metric<L> scoreCalculator,
-                                       Ignite ignite,
-                                       IgniteCache<K, V> upstreamCache,
-                                       IgniteBiPredicate<K, V> filter,
-                                       int amountOfFolds,
-                                       ParamGrid paramGrid) {
-
-        List<Double[]> paramSets = new ParameterSetGenerator(paramGrid.getParamValuesByParamIdx()).generate();
-
-        CrossValidationResult cvRes = new CrossValidationResult();
-
-        DatasetTrainer trainer = pipeline.getTrainer();
-
-        paramSets.forEach(paramSet -> {
-            Map<String, Double> paramMap = new HashMap<>();
-
-            for (int paramIdx = 0; paramIdx < paramSet.length; paramIdx++) {
-                String paramName = paramGrid.getParamNameByIndex(paramIdx);
-                Double paramVal = paramSet[paramIdx];
-
-                paramMap.put(paramName, paramVal);
-
-                try {
-                    final String mtdName = "with" +
-                        paramName.substring(0, 1).toUpperCase() +
-                        paramName.substring(1);
-
-                    Method trainerSetter = null;
-
-                    // We should iterate along all methods due to we have no info about signature and passed types.
-                    for (Method method : trainer.getClass().getDeclaredMethods()) {
-                        if (method.getName().equals(mtdName))
-                            trainerSetter = method;
-                    }
-
-                    if (trainerSetter != null)
-                        trainerSetter.invoke(trainer, paramVal);
-                    else
-                        throw new NoSuchMethodException(mtdName);
-
-                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
-                    e.printStackTrace();
-                }
-            }
-
-            double[] locScores = scorePipeline(
-                pipeline,
-                predicate -> new CacheBasedDatasetBuilder<>(
-                    ignite,
-                    upstreamCache,
-                    (k, v) -> filter.apply(k, v) && predicate.apply(k, v)
-                ),
-                (predicate, mdl) -> new CacheBasedLabelPairCursor<>(
-                    upstreamCache,
-                    (k, v) -> filter.apply(k, v) && !predicate.apply(k, v),
-                    ((PipelineMdl<K, V>) mdl).getPreprocessor(),
-                    mdl
-                ),
-                scoreCalculator,
-                new SHA256UniformMapper<>(),
-                amountOfFolds
-            );
-
-            cvRes.addScores(locScores, paramMap);
-
-            final double locAvgScore = Arrays.stream(locScores).average().orElse(Double.MIN_VALUE);
-
-            if (locAvgScore > cvRes.getBestAvgScore()) {
-                cvRes.setBestScore(locScores);
-                cvRes.setBestHyperParams(paramMap);
-                System.out.println(paramMap.toString());
-            }
-        });
-
-        return cvRes;
-
+    public CrossValidation<M, L, K, V> withIgnite(Ignite ignite) {
+        this.ignite = ignite;
+        return this;
     }
 
     /**
-     * Computes cross-validated metrics.
-     *
-     * @param pipeline               Pipeline of stages.
-     * @param datasetBuilderSupplier Dataset builder supplier.
-     * @param testDataIterSupplier   Test data iterator supplier.
-     * @param scoreCalculator        Base score calculator.
-     * @param mapper                 Mapper used to map a key-value pair to a point on the segment (0, 1).
-     * @param cv                     Number of folds.
-     * @return Array of scores of the estimator for each run of the cross validation.
+     * @param upstreamCache Upstream cache.
      */
-    private double[] scorePipeline(Pipeline<K, V, Integer, Double> pipeline,
-                                   Function<IgniteBiPredicate<K, V>, DatasetBuilder<K, V>> datasetBuilderSupplier,
-                                   BiFunction<IgniteBiPredicate<K, V>, M, LabelPairCursor<L>> testDataIterSupplier,
-                                   Metric<L> scoreCalculator,
-                                   UniformMapper<K, V> mapper,
-                                   int cv
-    ) {
-
-        double[] scores = new double[cv];
-
-        double foldSize = 1.0 / cv;
-        for (int i = 0; i < cv; i++) {
-            double from = foldSize * i;
-            double to = foldSize * (i + 1);
-
-            IgniteBiPredicate<K, V> trainSetFilter = (k, v) -> {
-                double pnt = mapper.map(k, v);
-                return pnt < from || pnt > to;
-            };
-
-            DatasetBuilder<K, V> datasetBuilder = datasetBuilderSupplier.apply(trainSetFilter);
-            PipelineMdl<K, V> mdl = pipeline.fit(datasetBuilder);
-
-            try (LabelPairCursor<L> cursor = testDataIterSupplier.apply(trainSetFilter, (M) mdl)) {
-                scores[i] = scoreCalculator.score(cursor.iterator());
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        return scores;
+    public CrossValidation<M, L, K, V> withUpstreamCache(IgniteCache<K, V> upstreamCache) {
+        this.upstreamCache = upstreamCache;
+        return this;
     }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/CrossValidationResult.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/CrossValidationResult.java
index 6f11eb6..f7ddae3 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/CrossValidationResult.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/CrossValidationResult.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.ml.selection.cv;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -40,18 +41,12 @@ public class CrossValidationResult {
     private Map<Map<String, Double>, double[]> scoringBoard = new HashMap<>();
 
     /**
-     * Default constructor.
-     */
-    CrossValidationResult() {
-    }
-
-    /**
      * Gets the best value for the specific hyper parameter.
      *
      * @param hyperParamName Hyper parameter name.
      * @return The value.
      */
-    public double getBest(String hyperParamName) {
+    public synchronized double getBest(String hyperParamName) {
         return bestHyperParams.get(hyperParamName);
     }
 
@@ -60,7 +55,7 @@ public class CrossValidationResult {
      *
      * @return The value.
      */
-    public double[] getBestScore() {
+    public synchronized double[] getBestScore() {
         return bestScore;
     }
 
@@ -70,16 +65,18 @@ public class CrossValidationResult {
      * @param locScores The scores.
      * @param paramMap  The parameter set associated with the given scores.
      */
-    void addScores(double[] locScores, Map<String, Double> paramMap) {
+    synchronized void addScores(double[] locScores, Map<String, Double> paramMap) {
         scoringBoard.put(paramMap, locScores);
     }
 
     /**
      * Gets the the average value of best score array.
      *
+     * Default value is Double.MIN_VALUE.
+     *
      * @return The value.
      */
-    public double getBestAvgScore() {
+    public synchronized double getBestAvgScore() {
         if (bestScore == null)
             return Double.MIN_VALUE;
         return Arrays.stream(bestScore).average().orElse(Double.MIN_VALUE);
@@ -90,7 +87,7 @@ public class CrossValidationResult {
      *
      * @param bestScore The best score.
      */
-    void setBestScore(double[] bestScore) {
+    synchronized void setBestScore(double[] bestScore) {
         this.bestScore = bestScore;
     }
 
@@ -99,7 +96,7 @@ public class CrossValidationResult {
      *
      * @param bestHyperParams The best hyper parameters.
      */
-    void setBestHyperParams(Map<String, Double> bestHyperParams) {
+    public synchronized void setBestHyperParams(Map<String, Double> bestHyperParams) {
         this.bestHyperParams = bestHyperParams;
     }
 
@@ -111,8 +108,8 @@ public class CrossValidationResult {
      *
      * @return The Scoring Board.
      */
-    public Map<Map<String, Double>, double[]> getScoringBoard() {
-        return scoringBoard;
+    public synchronized Map<Map<String, Double>, double[]> getScoringBoard() {
+        return Collections.unmodifiableMap(scoringBoard);
     }
 
     /**
@@ -120,12 +117,12 @@ public class CrossValidationResult {
      *
      * @return The value.
      */
-    public Map<String, Double> getBestHyperParams() {
-        return bestHyperParams;
+    public synchronized Map<String, Double> getBestHyperParams() {
+        return Collections.unmodifiableMap(bestHyperParams);
     }
 
     /** {@inheritDoc} */
-    @Override public String toString() {
+    @Override public synchronized String toString() {
         return "CrossValidationResult{" +
             "bestHyperParams=" + bestHyperParams +
             ", bestScore=" + Arrays.toString(bestScore) +
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/DebugCrossValidation.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/DebugCrossValidation.java
new file mode 100644
index 0000000..6a1ba27
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/cv/DebugCrossValidation.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ml.selection.cv;
+
+import java.util.Map;
+import org.apache.ignite.ml.IgniteModel;
+import org.apache.ignite.ml.dataset.impl.local.LocalDatasetBuilder;
+import org.apache.ignite.ml.math.primitives.vector.Vector;
+import org.apache.ignite.ml.selection.scoring.cursor.LocalLabelPairCursor;
+
+/**
+ * Cross validation score calculator. Cross validation is an approach that allows to avoid overfitting that is made the
+ * following way: the training set is split into k smaller sets. The following procedure is followed for each of the k
+ * “folds”:
+ * <ul>
+ * <li>A model is trained using k-1 of the folds as training data;</li>
+ * <li>the resulting model is validated on the remaining part of the data (i.e., it is used as a test set to compute
+ * a performance measure such as accuracy).</li>
+ * </ul>
+ *
+ * @param <M> Type of model.
+ * @param <L> Type of a label (truth or prediction).
+ * @param <K> Type of a key in {@code upstream} data.
+ * @param <V> Type of a value in {@code upstream} data.
+ */
+public class DebugCrossValidation<M extends IgniteModel<Vector, L>, L, K, V> extends AbstractCrossValidation<M, L, K, V> {
+    /** Upstream map. */
+    private Map<K, V> upstreamMap;
+
+    /** Parts. */
+    private int parts;
+
+    /**
+     * Calculates score by folds.
+     */
+    @Override public double[] scoreByFolds() {
+        double[] locScores;
+
+        locScores = isRunningOnPipeline ? scorePipelineLocally() : scoreLocally();
+
+        return locScores;
+    }
+
+    /**
+     * Calculate score on pipeline based on local data (upstream map).
+     *
+     * @return Array of scores of the estimator for each run of the cross validation.
+     */
+    private double[] scorePipelineLocally() {
+        return scorePipeline(
+            predicate -> new LocalDatasetBuilder<>(
+                upstreamMap,
+                (k, v) -> filter.apply(k, v) && predicate.apply(k, v),
+                parts
+            ),
+            (predicate, mdl) -> new LocalLabelPairCursor<>(
+                upstreamMap,
+                (k, v) -> filter.apply(k, v) && !predicate.apply(k, v),
+                preprocessor,
+                mdl
+            )
+        );
+    }
+
+    /**
+     * Computes cross-validated metrics.
+     *
+     * @return Array of scores of the estimator for each run of the cross validation.
+     */
+    private double[] scoreLocally() {
+        return score(
+            predicate -> new LocalDatasetBuilder<>(
+                upstreamMap,
+                (k, v) -> filter.apply(k, v) && predicate.apply(k, v),
+                parts
+            ),
+            (predicate, mdl) -> new LocalLabelPairCursor<>(
+                upstreamMap,
+                (k, v) -> filter.apply(k, v) && !predicate.apply(k, v),
+                preprocessor,
+                mdl
+            )
+        );
+    }
+
+    /**
+     * @param upstreamMap Upstream map.
+     */
+    public DebugCrossValidation<M, L, K, V> withUpstreamMap(Map<K, V> upstreamMap) {
+        this.upstreamMap = upstreamMap;
+        return this;
+    }
+
+    /**
+     * @param parts Parts.
+     */
+    public DebugCrossValidation<M, L, K, V> withAmountOfParts(int parts) {
+        this.parts = parts;
+        return this;
+    }
+}
\ No newline at end of file
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/BruteForceStrategy.java
similarity index 73%
copy from modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
copy to modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/BruteForceStrategy.java
index 201ab5d..fbc7a72 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/BruteForceStrategy.java
@@ -15,17 +15,14 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ml.util;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+package org.apache.ignite.ml.selection.paramgrid;
 
 /**
- * Test suite for all tests located in {@link org.apache.ignite.ml.util} package.
+ * This strategy enables the brute-force search in hyper-parameter space.
  */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    LRUCacheTest.class
-})
-public class UtilTestSuite {
-}
+public class BruteForceStrategy extends HyperParameterTuningStrategy {
+    /** {@inheritDoc} */
+    @Override public String getName() {
+        return "Brute Force";
+    }
+}
\ No newline at end of file
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/EvolutionOptimizationStrategy.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/EvolutionOptimizationStrategy.java
new file mode 100644
index 0000000..11869cd
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/EvolutionOptimizationStrategy.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ml.selection.paramgrid;
+
+import org.apache.ignite.ml.util.genetic.CrossoverStrategy;
+import org.apache.ignite.ml.util.genetic.SelectionStrategy;
+
+/** Represents the Genetic algorithms usage for finding the best set of hyper-parameters. */
+public class EvolutionOptimizationStrategy extends HyperParameterTuningStrategy {
+    /** Seed. */
+    private long seed = 1234L;
+
+    /** Amount of elite chromosomes. */
+    private int amountOfEliteChromosomes = 2;
+
+    /** Amount of generations. */
+    private int amountOfGenerations = 10;
+
+    /** Crossingover probability. */
+    private double crossingoverProbability = 0.9;
+
+    /** Mutation probability. */
+    private double mutationProbability = 0.1;
+
+    /** Crossover strategy. */
+    private CrossoverStrategy crossoverStgy = CrossoverStrategy.UNIFORM;
+
+    /** Selection strategy. */
+    private SelectionStrategy selectionStgy = SelectionStrategy.ROULETTE_WHEEL;
+
+    /**
+     *
+     */
+    public long getSeed() {
+        return seed;
+    }
+
+    /**
+     *
+     */
+    public int getAmountOfGenerations() {
+        return amountOfGenerations;
+    }
+
+    /**
+     *
+     */
+    public int getAmountOfEliteChromosomes() {
+        return amountOfEliteChromosomes;
+    }
+
+    /**
+     *
+     */
+    public double getCrossingoverProbability() {
+        return crossingoverProbability;
+    }
+
+    /**
+     *
+     */
+    public double getMutationProbability() {
+        return mutationProbability;
+    }
+
+    /**
+     *
+     */
+    public CrossoverStrategy getCrossoverStgy() {
+        return crossoverStgy;
+    }
+
+    /**
+     *
+     */
+    public SelectionStrategy getSelectionStgy() {
+        return selectionStgy;
+    }
+
+    /**
+     * Set up the seed number.
+     *
+     * @param seed Seed.
+     */
+    public EvolutionOptimizationStrategy withSeed(long seed) {
+        this.seed = seed;
+        return this;
+    }
+
+    /**
+     * @param crossingoverProbability Crossingover probability.
+     */
+    public EvolutionOptimizationStrategy withCrossingoverProbability(double crossingoverProbability) {
+        this.crossingoverProbability = crossingoverProbability;
+        return this;
+    }
+
+    /**
+     * @param mutationProbability Mutation probability.
+     */
+    public EvolutionOptimizationStrategy withMutationProbability(double mutationProbability) {
+        this.mutationProbability = mutationProbability;
+        return this;
+    }
+
+    /**
+     * @param crossoverStgy Crossover strategy.
+     */
+    public EvolutionOptimizationStrategy withCrossoverStgy(CrossoverStrategy crossoverStgy) {
+        this.crossoverStgy = crossoverStgy;
+        return this;
+    }
+
+    /**
+     * @param selectionStgy Selection strategy.
+     */
+    public EvolutionOptimizationStrategy withSelectionStgy(SelectionStrategy selectionStgy) {
+        this.selectionStgy = selectionStgy;
+        return this;
+    }
+
+
+    /** {@inheritDoc} */
+    @Override public String getName() {
+        return "Evolution Optimization";
+    }
+}
\ No newline at end of file
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/HyperParameterTuningStrategy.java
similarity index 74%
copy from modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
copy to modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/HyperParameterTuningStrategy.java
index 201ab5d..2d5b6b8 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/HyperParameterTuningStrategy.java
@@ -15,17 +15,14 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ml.util;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+package org.apache.ignite.ml.selection.paramgrid;
 
 /**
- * Test suite for all tests located in {@link org.apache.ignite.ml.util} package.
+ * The parent abstract class of all hyper-parameter tuning strategies.
  */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    LRUCacheTest.class
-})
-public class UtilTestSuite {
+public abstract class HyperParameterTuningStrategy {
+    /**
+     * Returns the name of strategy.
+     */
+    public abstract String getName();
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/ParamGrid.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/ParamGrid.java
index f9c5bd2..48a0af1 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/ParamGrid.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/ParamGrid.java
@@ -17,8 +17,12 @@
 
 package org.apache.ignite.ml.selection.paramgrid;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.function.DoubleConsumer;
 
 /**
  * Keeps the grid of parameters.
@@ -28,31 +32,69 @@ public class ParamGrid {
     private Map<Integer, Double[]> paramValuesByParamIdx = new HashMap<>();
 
     /** Parameter names by parameter index. */
+    private Map<Integer, DoubleConsumer> settersByParamIdx = new HashMap<>();
+
+    /** Parameter names by parameter index. */
     private Map<Integer, String> paramNamesByParamIdx = new HashMap<>();
 
     /** Parameter counter. */
     private int paramCntr;
 
+    /** Parameter search strategy. */
+    private HyperParameterTuningStrategy paramSearchStgy = new BruteForceStrategy();
+
     /** */
     public Map<Integer, Double[]> getParamValuesByParamIdx() {
-        return paramValuesByParamIdx;
+        return Collections.unmodifiableMap(paramValuesByParamIdx);
     }
 
     /**
      * Adds a grid for the specific hyper parameter.
      * @param paramName The parameter name.
+     * @param setter The method reference to trainer or preprocessor trainer setter.
      * @param params The array of the given hyper parameter values.
      * @return The updated ParamGrid.
      */
-    public ParamGrid addHyperParam(String paramName, Double[] params) {
+    public ParamGrid addHyperParam(String paramName, DoubleConsumer setter, Double[] params) {
         paramValuesByParamIdx.put(paramCntr, params);
         paramNamesByParamIdx.put(paramCntr, paramName);
+        settersByParamIdx.put(paramCntr, setter);
         paramCntr++;
         return this;
     }
 
-    /** */
+    /**
+     * Set up the hyperparameter searching strategy.
+     *
+     * @param paramSearchStgy Parameter search strategy.
+     */
+    public ParamGrid withParameterSearchStrategy(HyperParameterTuningStrategy paramSearchStgy) {
+        this.paramSearchStgy = paramSearchStgy;
+        return this;
+    }
+
+
+    /** Returns the Hyper-parameter tuning strategy. */
+    public HyperParameterTuningStrategy getHyperParameterTuningStrategy() {
+        return paramSearchStgy;
+    }
+
+    /** Returns setter for parameter with the given index. */
+    public DoubleConsumer getSetterByIndex(int idx) {
+        return settersByParamIdx.get(idx);
+    }
+
+    /** Returns the name of hyper-parameter by the given index. */
     public String getParamNameByIndex(int idx) {
         return paramNamesByParamIdx.get(idx);
     }
+
+    /**
+     * Prepare data for hyper-parameter tuning.
+     */
+    public List<Double[]> getParamRawData() {
+        List<Double[]> res = new ArrayList<>();
+        paramValuesByParamIdx.forEach(res::add);
+        return res;
+    }
 }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/ParameterSetGenerator.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/ParameterSetGenerator.java
index b6c86a1..0aedfbf 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/ParameterSetGenerator.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/ParameterSetGenerator.java
@@ -19,6 +19,7 @@ package org.apache.ignite.ml.selection.paramgrid;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -49,7 +50,7 @@ public class ParameterSetGenerator {
         assert !map.isEmpty();
 
         this.map = map;
-        this.sizeOfParamVector = map.size();
+        sizeOfParamVector = map.size();
     }
 
     /**
@@ -61,7 +62,7 @@ public class ParameterSetGenerator {
 
         traverseTree(map, nextPnt, -1);
 
-        return params;
+        return Collections.unmodifiableList(params);
     }
 
     /**
@@ -76,7 +77,6 @@ public class ParameterSetGenerator {
 
         if (dimensionNum == sizeOfParamVector){
             Double[] paramSet = Arrays.copyOf(nextPnt, sizeOfParamVector);
-            System.out.println(Arrays.toString(paramSet));
             params.add(paramSet);
             return;
         }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/RandomStrategy.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/RandomStrategy.java
new file mode 100644
index 0000000..5f6d7d3
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/paramgrid/RandomStrategy.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ml.selection.paramgrid;
+
+/**
+ * This strategy enables the random search in hyper-parameter space.
+ */
+public class RandomStrategy extends HyperParameterTuningStrategy {
+    /** Satisfactory fitness to stop the hyperparameter search. */
+    private double satisfactoryFitness = 0.5;
+
+    /** Max tries to stop the hyperparameter search. */
+    private int maxTries = 100;
+
+    /** Seed. */
+    private long seed = 1234L;
+
+    /** Returns the seed. */
+    public long getSeed() {
+        return seed;
+    }
+
+    /**
+     * Set up the seed number.
+     *
+     * @param seed Seed.
+     */
+    public RandomStrategy withSeed(long seed) {
+        this.seed = seed;
+        return this;
+    }
+
+    /**
+     *
+     */
+    public double getSatisfactoryFitness() {
+        return satisfactoryFitness;
+    }
+
+    /**
+     * Set up the satisfactory fitness to stop the hyperparameter search.
+     *
+     * @param fitness Fitness.
+     */
+    public RandomStrategy withSatisfactoryFitness(double fitness) {
+        satisfactoryFitness = fitness;
+        return this;
+    }
+
+    /** Returns the max number of tries to stop the hyperparameter search. */
+    public int getMaxTries() {
+        return maxTries;
+    }
+
+    /**
+     * Set up the max number of tries to stop the hyperparameter search.
+     *
+     * @param maxTries Max tries.
+     */
+    public RandomStrategy withMaxTries(int maxTries) {
+        this.maxTries = maxTries;
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getName() {
+        return "Random Search";
+    }
+}
\ No newline at end of file
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/cursor/CacheBasedLabelPairCursor.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/cursor/CacheBasedLabelPairCursor.java
index 818a84e..32a24d8 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/cursor/CacheBasedLabelPairCursor.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/cursor/CacheBasedLabelPairCursor.java
@@ -58,7 +58,7 @@ public class CacheBasedLabelPairCursor<L, K, V> implements LabelPairCursor<L> {
     public CacheBasedLabelPairCursor(IgniteCache<K, V> upstreamCache, IgniteBiPredicate<K, V> filter,
                                      Preprocessor<K, V> preprocessor,
                                      IgniteModel<Vector, L> mdl) {
-        this.cursor = query(upstreamCache, filter);
+        cursor = query(upstreamCache, filter);
         this.preprocessor = preprocessor;
         this.mdl = mdl;
     }
@@ -73,7 +73,7 @@ public class CacheBasedLabelPairCursor<L, K, V> implements LabelPairCursor<L> {
     public CacheBasedLabelPairCursor(IgniteCache<K, V> upstreamCache,
                                      Preprocessor<K, V> preprocessor,
                                      IgniteModel<Vector, L> mdl) {
-        this.cursor = query(upstreamCache);
+        cursor = query(upstreamCache);
         this.preprocessor = preprocessor;
         this.mdl = mdl;
     }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/cursor/LocalLabelPairCursor.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/cursor/LocalLabelPairCursor.java
index a9221ae..f0be6ca 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/cursor/LocalLabelPairCursor.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/cursor/LocalLabelPairCursor.java
@@ -97,7 +97,7 @@ public class LocalLabelPairCursor<L, K, V, T> implements LabelPairCursor<L> {
         @Override public boolean hasNext() {
             if (filter == null) {
                 Map.Entry<K, V> entry = iter.next();
-                this.nextEntry = entry;
+                nextEntry = entry;
                 return iter.hasNext();
             }
 
@@ -130,7 +130,7 @@ public class LocalLabelPairCursor<L, K, V, T> implements LabelPairCursor<L> {
                 Map.Entry<K, V> entry = iter.next();
 
                 if (filter.apply(entry.getKey(), entry.getValue())) {
-                    this.nextEntry = entry;
+                    nextEntry = entry;
                     break;
                 }
             }
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/MetricValues.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/MetricValues.java
index 7241ee1..c942d96 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/MetricValues.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/MetricValues.java
@@ -28,14 +28,14 @@ public interface MetricValues {
     /** Returns the pair of metric name and metric value. */
     public default Map<String, Double> toMap() {
         Map<String, Double> metricValues = new HashMap<>();
-        Class<? extends MetricValues> aClass = getClass();
-        for (Field field : aClass.getDeclaredFields()) {
+        Class<? extends MetricValues> aCls = getClass();
+        for (Field field : aCls.getDeclaredFields()) {
             try {
                 field.setAccessible(true);
                 metricValues.put(field.getName(), field.getDouble(this));
             }
             catch (IllegalAccessException e) {
-                throw new RuntimeException("Cannot read field [class=" + aClass.getSimpleName() + ", field_name=" + field.getName() + "]", e);
+                throw new RuntimeException("Cannot read field [class=" + aCls.getSimpleName() + ", field_name=" + field.getName() + "]", e);
             }
         }
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/classification/BinaryClassificationMetrics.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/classification/BinaryClassificationMetrics.java
index e1966bd..b941613 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/classification/BinaryClassificationMetrics.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/classification/BinaryClassificationMetrics.java
@@ -42,7 +42,6 @@ public class BinaryClassificationMetrics extends AbstractMetrics<BinaryClassific
     {
         metric = BinaryClassificationMetricValues::accuracy;
     }
-
     /**
      * Calculates binary metrics values.
      *
@@ -122,7 +121,7 @@ public class BinaryClassificationMetrics extends AbstractMetrics<BinaryClassific
 
     /** */
     public BinaryClassificationMetrics withEnablingROCAUC(boolean enableROCAUC) {
-        this.enableROCAUC = this.enableROCAUC;
+        this.enableROCAUC = enableROCAUC;
         return this;
     }
 
@@ -131,7 +130,6 @@ public class BinaryClassificationMetrics extends AbstractMetrics<BinaryClassific
         return enableROCAUC;
     }
 
-
     /** {@inheritDoc} */
     @Override public String name() {
         return "Binary classification metrics";
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/regression/RegressionMetrics.java b/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/regression/RegressionMetrics.java
index a0eaedf..1e80cee 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/regression/RegressionMetrics.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/selection/scoring/metric/regression/RegressionMetrics.java
@@ -66,14 +66,8 @@ public class RegressionMetrics extends AbstractMetrics<RegressionMetricValues> {
         double tss = totalAmount * (meanOfLblSquares - Math.pow(meanOfLbls, 2));
 
         double r2 = 0.0;
-        if (Math.abs(tss) < EPS) {
-            if (Math.abs(rss) < EPS)
-                r2 = 1.0;
-            else
-                r2 = 0.0;
-        } else {
-            r2 = 1 - rss / tss;
-        }
+        if (Math.abs(tss) < EPS) r2 = Math.abs(rss) < EPS ? 1.0 : 0.0;
+        else r2 = 1 - rss / tss;
 
         mae /= totalAmount;
 
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeClassificationTrainer.java b/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeClassificationTrainer.java
index 321e65f..688fd50 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeClassificationTrainer.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/tree/DecisionTreeClassificationTrainer.java
@@ -96,6 +96,24 @@ public class DecisionTreeClassificationTrainer extends DecisionTree<GiniImpurity
         return this;
     }
 
+    /**
+     * Returns a hyper-parameter value.
+     *
+     * @return The max deep of tree.
+     */
+    public double getMaxDeep() {
+        return maxDeep;
+    }
+
+    /**
+     * Returns a hyper-parameter value.
+     *
+     * @return The min impurity decrease.
+     */
+    public double getMinImpurityDecrease() {
+        return minImpurityDecrease;
+    }
+
     /** {@inheritDoc} */
     @Override protected ImpurityMeasureCalculator<GiniImpurityMeasure> getImpurityMeasureCalculator(
         Dataset<EmptyContext, DecisionTreeData> dataset) {
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/Chromosome.java b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/Chromosome.java
new file mode 100644
index 0000000..778885f
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/Chromosome.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ml.util.genetic;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Representes the set of genes, known as chromosome in genetic programming.
+ *
+ * Note: this class has a natural ordering that is inconsistent with equals.
+ */
+public class Chromosome implements Comparable {
+    /** Genes. */
+    private Double[] genes;
+
+    /** Fitness. */
+    private Double fitness = Double.NaN;
+
+    /**
+     * @param size Size.
+     */
+    public Chromosome(int size) {
+        this.genes = new Double[size];
+    }
+
+    /**
+     * @param doubles Doubles.
+     */
+    public Chromosome(Double[] doubles) {
+        genes = doubles.clone();
+    }
+
+    /**
+     * Returns the double array chromosome representation.
+     */
+    public Double[] toDoubleArray() {
+        return genes;
+    }
+
+    /**
+     * Returns the fitness value.
+     */
+    public Double getFitness() {
+        return fitness;
+    }
+
+    /**
+     * Sets the fitness value.
+     *
+     * @param fitness Fitness.
+     */
+    public void setFitness(Double fitness) {
+        this.fitness = fitness;
+    }
+
+    /**
+     * Returns the amount of genes in chromosome.
+     */
+    public int size() {
+        return genes.length;
+    }
+
+    /**
+     * Returns the gene value by index.
+     *
+     * @param idx Index.
+     */
+    public double getGene(int idx) {
+        return genes[idx];
+    }
+
+    /**
+     * Sets gene value by index.
+     *
+     * @param idx       Index.
+     * @param geneValue Gene value.
+     */
+    public void setGene(int idx, double geneValue) {
+        genes[idx] = geneValue;
+    }
+
+    /**
+     * Creates chromosome copy.
+     */
+    public Chromosome copy() {
+        Chromosome cp = new Chromosome(genes);
+        cp.fitness = fitness;
+        return cp;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int compareTo(@NotNull Object o) {
+        return (int) Math.signum(getFitness() - ((Chromosome) o).getFitness());
+    }
+}
\ No newline at end of file
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/CrossoverStrategy.java
similarity index 73%
copy from modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
copy to modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/CrossoverStrategy.java
index 201ab5d..a925646 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/CrossoverStrategy.java
@@ -15,17 +15,21 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ml.util;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+package org.apache.ignite.ml.util.genetic;
 
 /**
- * Test suite for all tests located in {@link org.apache.ignite.ml.util} package.
+ * Represents the crossover strategy depending of locus point amount.
  */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    LRUCacheTest.class
-})
-public class UtilTestSuite {
-}
+public enum CrossoverStrategy {
+    /** One point. */
+    ONE_POINT,
+
+    /** Two point. */
+    TWO_POINT,
+
+    /** Multi point. */
+    MULTI_POINT,
+
+    /** Uniform. */
+    UNIFORM
+}
\ No newline at end of file
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/GeneticAlgorithm.java b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/GeneticAlgorithm.java
new file mode 100644
index 0000000..bd351a5
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/GeneticAlgorithm.java
@@ -0,0 +1,451 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ml.util.genetic;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.commons.math3.util.Pair;
+import org.apache.ignite.ml.environment.LearningEnvironment;
+import org.apache.ignite.ml.environment.parallelism.Promise;
+import org.apache.ignite.ml.math.functions.IgniteSupplier;
+
+/**
+ * This class is an entry point to use Genetic Algorithm to solve optimization problem.
+ */
+public class GeneticAlgorithm {
+    /** Uniform rate. */
+    private static final double UNIFORM_RATE = 0.5;
+
+    /** Population size. */
+    private int populationSize;
+
+    /** Amount of elite chromosomes. */
+    private int amountOfEliteChromosomes = 2;
+
+    /** Amount of generations. */
+    private int amountOfGenerations = 10;
+
+    /** Seed. */
+    private long seed = 123L;
+
+    /** Crossingover probability. */
+    private double crossingoverProbability = 0.9;
+
+    /** Mutation probability. */
+    private double mutationProbability = 0.1;
+
+    /** Random generator. */
+    private Random rnd = new Random(seed);
+
+    /** Population. */
+    private Population population;
+
+    /** Fitness function. */
+    private Function<Chromosome, Double> fitnessFunction;
+
+    /** Mutation operator. */
+    private BiFunction<Integer, Double, Double> mutationOperator;
+
+    /** Crossover strategy. */
+    private CrossoverStrategy crossoverStgy = CrossoverStrategy.UNIFORM;
+
+    /** Selection strategy. */
+    private SelectionStrategy selectionStgy = SelectionStrategy.ROULETTE_WHEEL;
+
+    /**
+     * @param paramSet The list of sets of parameter's values.
+     */
+    public GeneticAlgorithm(List<Double[]> paramSet) {
+        initializePopulation(paramSet);
+    }
+
+    /**
+     * Forms the initial population.
+     *
+     * @param rawDataForPopulationFormation Rnd parameter sets.
+     */
+    private Population initializePopulation(List<Double[]> rawDataForPopulationFormation) {
+        // validate that population size should be even
+        // elite chromosome should be even too or we should handle odd case especially
+        populationSize = rawDataForPopulationFormation.size();
+        population = new Population(populationSize);
+        for (int i = 0; i < populationSize; i++)
+            population.setChromosome(i, new Chromosome(rawDataForPopulationFormation.get(i)));
+
+        return population;
+    }
+
+    /**
+     * The main method for genetic algorithm.
+     */
+    public void run() {
+        if (population != null) {
+            population.calculateFitnessForAll(fitnessFunction);
+            int i = 0;
+            while (stopCriteriaIsReached(i)) {
+                Population newPopulation = new Population(populationSize);
+
+                newPopulation = selectEliteChromosomes(newPopulation);
+
+                Population parents = selectionParents();
+
+                newPopulation = crossingover(parents, newPopulation);
+
+                newPopulation = mutate(newPopulation);
+
+                // update fitness for new population
+                for (int j = amountOfEliteChromosomes; j < populationSize; j++)
+                    newPopulation.calculateFitnessForChromosome(j, fitnessFunction);
+
+                population = newPopulation;
+
+                i++;
+            }
+        }
+    }
+
+    /**
+     * The main method for genetic algorithm.
+     *
+     * @param environment The environment.
+     */
+    public void runParallel(LearningEnvironment environment) {
+        if (population != null) {
+            population.calculateFitnessForAll(fitnessFunction); // TODO: parallelize this
+            int i = 0;
+            while (stopCriteriaIsReached(i)) {
+                Population newPopulation = new Population(populationSize);
+
+                newPopulation = selectEliteChromosomes(newPopulation);
+
+                Population parents = selectionParents();
+
+                newPopulation = crossingover(parents, newPopulation);
+
+                newPopulation = mutate(newPopulation);
+
+                // update fitness for new population
+                List<IgniteSupplier<Pair<Integer, Double>>> tasks = new ArrayList<>();
+                for (int j = amountOfEliteChromosomes; j < populationSize; j++) {
+                    int finalJ = j;
+                    Population finalNewPopulation1 = newPopulation;
+                    IgniteSupplier<Pair<Integer, Double>> task = () -> new Pair<>(finalJ, fitnessFunction.apply(finalNewPopulation1.getChromosome(finalJ)));
+                    tasks.add(task);
+                }
+
+                List<Pair<Integer, Double>> taskResults = environment.parallelismStrategy().submit(tasks).stream()
+                    .map(Promise::unsafeGet)
+                    .collect(Collectors.toList());
+
+                Population finalNewPopulation = newPopulation;
+                taskResults.forEach(p -> finalNewPopulation.setFitness(p.getKey(), p.getValue()));
+
+                population = newPopulation;
+
+                i++;
+            }
+        }
+    }
+
+    /**
+     * The common method of parent population building with different selection strategies.
+     */
+    private Population selectionParents() {
+        switch (selectionStgy) {
+            case ROULETTE_WHEEL:
+                return selectParentsByRouletteWheel();
+            default:
+                throw new UnsupportedOperationException("This strategy "
+                    + selectionStgy.name() + " is not supported yet.");
+        }
+    }
+
+    /**
+     * Form the parent population via wheel-roulette algorithm.
+     * For more information, please have a look http://www.edc.ncl.ac.uk/highlight/rhjanuary2007g02.php/.
+     */
+    private Population selectParentsByRouletteWheel() {
+        double totalFitness = population.getTotalFitness();
+        double[] sectors = new double[population.size()];
+
+        for (int i = 0; i < population.size(); i++)
+            sectors[i] = population.getChromosome(i).getFitness() / totalFitness;
+
+        Population parentPopulation = new Population(population.size());
+
+        for (int i = 0; i < parentPopulation.size(); i++) {
+            double rouletteVal = rnd.nextDouble();
+            double accumulatedSectorLen = 0.0;
+            int selectedChromosomeIdx = Integer.MIN_VALUE;
+            int sectorIdx = 0;
+
+            while (selectedChromosomeIdx == Integer.MIN_VALUE && sectorIdx < sectors.length) {
+                accumulatedSectorLen += sectors[sectorIdx];
+                if (rouletteVal < accumulatedSectorLen)
+                    selectedChromosomeIdx = sectorIdx;
+                sectorIdx++;
+            }
+
+            if (selectedChromosomeIdx == Integer.MIN_VALUE)
+                selectedChromosomeIdx = rnd.nextInt(population.size()); // or get last
+
+            parentPopulation.setChromosome(i, population.getChromosome(selectedChromosomeIdx));
+        }
+
+        return parentPopulation;
+    }
+
+    /**
+     * Simple stop criteria condition based on max amount of generations.
+     *
+     * @param iterationNum Iteration number.
+     */
+    private boolean stopCriteriaIsReached(int iterationNum) {
+        return iterationNum < amountOfGenerations;
+    }
+
+    /**
+     * Selects and injects the best chromosomes to form the elite of new population.
+     *
+     * @param newPopulation New population.
+     */
+    private Population selectEliteChromosomes(Population newPopulation) {
+        boolean elitism = amountOfEliteChromosomes > 0;
+
+        if (elitism) {
+            Chromosome[] elite = population.selectBestKChromosome(amountOfEliteChromosomes);
+            for (int i = 0; i < elite.length; i++)
+                newPopulation.setChromosome(i, elite[i]);
+        }
+        return newPopulation;
+    }
+
+    /**
+     * Forms the new population based on parent population with crossingover operator.
+     *
+     * @param parents       Parents.
+     * @param newPopulation New population.
+     */
+    private Population crossingover(Population parents, Population newPopulation) {
+        // because parent population is less than new population on amount of elite chromosome
+        for (int j = 0; j < populationSize - amountOfEliteChromosomes; j += 2) {
+            Chromosome ch1 = parents.getChromosome(j);
+            Chromosome ch2 = parents.getChromosome(j + 1);
+
+            if (rnd.nextDouble() < crossingoverProbability) {
+                List<Chromosome> twoChildren = crossover(ch1, ch2);
+                newPopulation.setChromosome(amountOfEliteChromosomes + j, twoChildren.get(0));
+                newPopulation.setChromosome(amountOfEliteChromosomes + j + 1, twoChildren.get(1));
+            } else {
+                newPopulation.setChromosome(amountOfEliteChromosomes + j, ch1);
+                newPopulation.setChromosome(amountOfEliteChromosomes + j + 1, ch2);
+            }
+        }
+        return newPopulation;
+    }
+
+
+    /**
+     * Applies mutation operator to each chromosome in population with mutation probability.
+     *
+     * @param newPopulation New population.
+     */
+    private Population mutate(Population newPopulation) {
+        for (int j = amountOfEliteChromosomes; j < populationSize; j++) {
+            Chromosome possibleMutant = newPopulation.getChromosome(j);
+            for (int geneIdx = 0; geneIdx < possibleMutant.size(); geneIdx++) {
+                if (rnd.nextDouble() < mutationProbability) {
+                    Double gene = possibleMutant.getGene(geneIdx);
+                    Double newGeneVal = mutationOperator.apply(geneIdx, gene);
+                    possibleMutant.setGene(geneIdx, newGeneVal);
+                }
+            }
+        }
+        return newPopulation;
+    }
+
+    /**
+     * Produce the two child chromsome from two parent chromosome according crossover strategy.
+     *
+     * @param firstParent  First parent.
+     * @param secondParent Second parent.
+     */
+    private List<Chromosome> crossover(Chromosome firstParent, Chromosome secondParent) {
+        if (firstParent.size() != secondParent.size())
+            throw new RuntimeException("Different length of hyper-parameter vectors!");
+        switch (crossoverStgy) {
+            case UNIFORM:
+                return uniformStrategy(firstParent, secondParent);
+            case ONE_POINT:
+                return onePointStrategy(firstParent, secondParent);
+            default:
+                throw new UnsupportedOperationException("This strategy "
+                    + crossoverStgy.name() + " is not supported yet.");
+
+        }
+
+    }
+
+    /**
+     * Produce the two child chromsome from two parent chromosome according one-point strategy.
+     *
+     * @param firstParent  First parent.
+     * @param secondParent Second parent.
+     */
+    private List<Chromosome> onePointStrategy(Chromosome firstParent, Chromosome secondParent) {
+        int size = firstParent.size();
+
+        Chromosome child1 = new Chromosome(size);
+        Chromosome child2 = new Chromosome(size);
+        int locusPnt = rnd.nextInt(size);
+
+        for (int i = 0; i < locusPnt; i++) {
+            child1.setGene(i, firstParent.getGene(i));
+            child2.setGene(i, secondParent.getGene(i));
+        }
+
+
+        for (int i = locusPnt; i < size; i++) {
+            child1.setGene(i, secondParent.getGene(i));
+            child2.setGene(i, firstParent.getGene(i));
+        }
+
+        List<Chromosome> res = new ArrayList<>();
+        res.add(child1);
+        res.add(child2);
+
+        return res;
+    }
+
+    /**
+     * Produce the two child chromsome from two parent chromosome according uniform strategy.
+     *
+     * @param firstParent  First parent.
+     * @param secondParent Second parent.
+     */
+    private List<Chromosome> uniformStrategy(Chromosome firstParent, Chromosome secondParent) {
+        int size = firstParent.size();
+
+        Chromosome child1 = new Chromosome(size);
+        Chromosome child2 = new Chromosome(size);
+
+        for (int i = 0; i < firstParent.size(); i++) {
+            if (rnd.nextDouble() < UNIFORM_RATE) {
+                child1.setGene(i, firstParent.getGene(i));
+                child2.setGene(i, secondParent.getGene(i));
+            } else {
+                child1.setGene(i, secondParent.getGene(i));
+                child2.setGene(i, firstParent.getGene(i));
+            }
+        }
+
+        List<Chromosome> res = new ArrayList<>();
+        res.add(child1);
+        res.add(child2);
+
+        return res;
+    }
+
+    /**
+     * Sets the custom fitness function.
+     *
+     * @param fitnessFunction Fitness function.
+     */
+    public GeneticAlgorithm withFitnessFunction(Function<Chromosome, Double> fitnessFunction) {
+        this.fitnessFunction = fitnessFunction;
+        return this;
+    }
+
+    /**
+     * Returns the best chromosome's genes presented as double array.
+     */
+    public double[] getTheBestSolution() {
+        Double[] boxed = population.selectBestKChromosome(1)[0].toDoubleArray();
+        return Stream.of(boxed).mapToDouble(Double::doubleValue).toArray();
+    }
+
+    /**
+     * @param amountOfEliteChromosomes Amount of elite chromosomes.
+     */
+    public GeneticAlgorithm withAmountOfEliteChromosomes(int amountOfEliteChromosomes) {
+        this.amountOfEliteChromosomes = amountOfEliteChromosomes;
+        return this;
+    }
+
+    /**
+     * @param amountOfGenerations Amount of generations.
+     */
+    public GeneticAlgorithm withAmountOfGenerations(int amountOfGenerations) {
+        this.amountOfGenerations = amountOfGenerations;
+        return this;
+    }
+
+    /**
+     * @param mutationOperator Mutation operator.
+     */
+    public GeneticAlgorithm withMutationOperator(
+        BiFunction<Integer, Double, Double> mutationOperator) {
+        this.mutationOperator = mutationOperator;
+        return this;
+    }
+
+    /**
+     * @param populationSize Population size.
+     */
+    public GeneticAlgorithm withPopulationSize(int populationSize) {
+        this.populationSize = populationSize;
+        return this;
+    }
+
+    /**
+     * @param crossingoverProbability Crossingover probability.
+     */
+    public GeneticAlgorithm withCrossingoverProbability(double crossingoverProbability) {
+        this.crossingoverProbability = crossingoverProbability;
+        return this;
+    }
+
+    /**
+     * @param mutationProbability Mutation probability.
+     */
+    public GeneticAlgorithm withMutationProbability(double mutationProbability) {
+        this.mutationProbability = mutationProbability;
+        return this;
+    }
+
+    /**
+     * @param crossoverStgy Crossover strategy.
+     */
+    public GeneticAlgorithm withCrossoverStgy(CrossoverStrategy crossoverStgy) {
+        this.crossoverStgy = crossoverStgy;
+        return this;
+    }
+
+    /**
+     * @param selectionStgy Selection strategy.
+     */
+    public GeneticAlgorithm withSelectionStgy(SelectionStrategy selectionStgy) {
+        this.selectionStgy = selectionStgy;
+        return this;
+    }
+}
\ No newline at end of file
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/Population.java b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/Population.java
new file mode 100644
index 0000000..7f57b30
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/Population.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ml.util.genetic;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.function.Function;
+
+/**
+ * Represents a populations of chromosomes.
+ */
+public class Population {
+    /** Chromosomes. */
+    private Chromosome[] chromosomes;
+
+    /** Fitness calculated flags. */
+    private BitSet fitnessCalculatedFlags;
+
+    /**
+     * @param size Size.
+     */
+    public Population(int size) {
+        chromosomes = new Chromosome[size];
+        fitnessCalculatedFlags = new BitSet(size);
+    }
+
+    /**
+     * Returns an individual chromosome.
+     *
+     * @param idx Index of chromosome.
+     */
+    public Chromosome getChromosome(int idx) {
+        return chromosomes[idx];
+    }
+
+    /**
+     * Calculates fitness for chromosome found by index with custom fitness function.
+     *
+     * @param idx             Index.
+     * @param fitnessFunction Fitness function.
+     */
+    public double calculateFitnessForChromosome(int idx, Function<Chromosome, Double> fitnessFunction) {
+        double fitness = fitnessFunction.apply(chromosomes[idx]);
+        chromosomes[idx].setFitness(fitness);
+        fitnessCalculatedFlags.set(idx);
+        return fitness;
+    }
+
+    /**
+     * Calculates fintness for all chromosomes with custom fitness function.
+     *
+     * @param fitnessFunction Fitness function.
+     */
+    public void calculateFitnessForAll(Function<Chromosome, Double> fitnessFunction) {
+        for (int i = 0; i < chromosomes.length; i++)
+            calculateFitnessForChromosome(i, fitnessFunction);
+    }
+
+    /**
+     * Sets the chromsome for given index.
+     *
+     * @param idx        Index.
+     * @param chromosome Chromosome.
+     */
+    public void setChromosome(int idx, Chromosome chromosome) {
+        chromosomes[idx] = chromosome;
+        if (!Double.isNaN(chromosome.getFitness())) fitnessCalculatedFlags.set(idx);
+
+    }
+
+    /**
+     * Returns the chromosome by given index.
+     *
+     * @param idx Index.
+     */
+    public Chromosome getChromosome(Integer idx) {
+        return chromosomes[idx];
+    }
+
+    /**
+     * Selects the top K chromosomes by fitness value from the smallest to the largest.
+     *
+     * @param k The amount of top chromosome with highest value of the fitness.
+     *
+     *          Returns null if not all fitnesses are calculated for all chromosomes.
+     */
+    public Chromosome[] selectBestKChromosome(int k) {
+        if (fitnessCalculatedFlags.cardinality() == chromosomes.length) {
+            Chromosome[] cp = Arrays.copyOf(chromosomes, chromosomes.length);
+            Arrays.sort(cp);
+            return Arrays.copyOfRange(cp, cp.length - k, cp.length);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the total fitness value of population or Double.NaN if not all fitnesses are calculated for all chromosomes.
+     */
+    public double getTotalFitness() {
+        if (fitnessCalculatedFlags.cardinality() == chromosomes.length) {
+            double totalFitness = 0.0;
+
+            for (int i = 0; i < chromosomes.length; i++)
+                totalFitness += chromosomes[i].getFitness();
+
+            return totalFitness;
+        }
+        return Double.NaN;
+    }
+
+    /**
+     * Returns the average fitness of population or Double.NaN if not all fitnesses are calculated for all chromosomes.
+     */
+    public double getAverageFitness() {
+        if (fitnessCalculatedFlags.cardinality() == chromosomes.length) {
+            double totalFitness = 0.0;
+
+            for (int i = 0; i < chromosomes.length; i++)
+                totalFitness += chromosomes[i].getFitness();
+
+            return totalFitness / chromosomes.length;
+        }
+        return Double.NaN;
+    }
+
+
+    /**
+     * Returns the size of population.
+     */
+    public int size() {
+        return chromosomes.length;
+    }
+
+    /**
+     * Sets the fitness value for chromosome with the given index.
+     *
+     * @param idx     Index.
+     * @param fitness Fitness.
+     */
+    public void setFitness(Integer idx, Double fitness) {
+        chromosomes[idx].setFitness(fitness);
+        fitnessCalculatedFlags.set(idx);
+    }
+}
\ No newline at end of file
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/SelectionStrategy.java
similarity index 73%
copy from modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
copy to modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/SelectionStrategy.java
index 201ab5d..86fe9f0 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/SelectionStrategy.java
@@ -15,17 +15,18 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ml.util;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+package org.apache.ignite.ml.util.genetic;
 
 /**
- * Test suite for all tests located in {@link org.apache.ignite.ml.util} package.
+ * Please, have a look at https://en.wikipedia.org/wiki/Selection_(genetic_algorithm).
  */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    LRUCacheTest.class
-})
-public class UtilTestSuite {
-}
+public enum SelectionStrategy {
+    /** Roulette wheel. */
+    ROULETTE_WHEEL,
+
+    /** Truncation. */
+    TRUNCATION,
+
+    /** Tournament. */
+    TOURNAMENT
+}
\ No newline at end of file
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/package-info.java
similarity index 74%
copy from modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
copy to modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/package-info.java
index 201ab5d..c10df20 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/util/genetic/package-info.java
@@ -15,17 +15,9 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ml.util;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
 
 /**
- * Test suite for all tests located in {@link org.apache.ignite.ml.util} package.
+ * <!-- Package description. -->
+ * Contains some genetic algorithms for discrete optimization task in ML module locally.
  */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    LRUCacheTest.class
-})
-public class UtilTestSuite {
-}
+package org.apache.ignite.ml.util.genetic;
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/common/TrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/common/TrainerTest.java
index 10ed9da..1079271 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/common/TrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/common/TrainerTest.java
@@ -17,13 +17,12 @@
 
 package org.apache.ignite.ml.common;
 
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 /**
  * Basic fields and methods for the trainer tests.
@@ -256,7 +255,7 @@ public class TrainerTest {
     };
 
     /** The data is easy separated with classifier by y = x. */
-    protected static final double[][] twoLinearlySeparableClasses = {
+    public static final double[][] twoLinearlySeparableClasses = {
         {0.0, -122.69914721554494, -152.90003228835155},
         {1.0, -988.7803093110984, 39.64498230320555},
         {1.0, -721.0342526056645, -167.29469954420483},
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainerTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainerTest.java
index 54e6aaa..6fb760e 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainerTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/preprocessing/encoding/EncoderTrainerTest.java
@@ -43,14 +43,14 @@ public class EncoderTrainerTest extends TrainerTest {
     @Test
     public void testFitOnStringCategorialFeatures() {
         Map<Integer, Vector> data = new HashMap<>();
-        data.put(1, new DenseVector(new Serializable[]{"Monday", "September"}));
-        data.put(2, new DenseVector(new Serializable[]{"Monday", "August"}));
-        data.put(3, new DenseVector(new Serializable[]{"Monday", "August"}));
-        data.put(4, new DenseVector(new Serializable[]{"Friday", "June"}));
-        data.put(5, new DenseVector(new Serializable[]{"Friday", "June"}));
-        data.put(6, new DenseVector(new Serializable[]{"Sunday", "August"}));
+        data.put(1, new DenseVector(new Serializable[]{1.0, "Monday", "September"}));
+        data.put(2, new DenseVector(new Serializable[]{2.0, "Monday", "August"}));
+        data.put(3, new DenseVector(new Serializable[]{3.0, "Monday", "August"}));
+        data.put(4, new DenseVector(new Serializable[]{4.0, "Friday", "June"}));
+        data.put(5, new DenseVector(new Serializable[]{5.0, "Friday", "June"}));
+        data.put(6, new DenseVector(new Serializable[]{6.0, "Sunday", "August"}));
 
-        final Vectorizer<Integer, Vector, Integer, Double> vectorizer = new DummyVectorizer<Integer>(0 , 1);
+        final Vectorizer<Integer, Vector, Integer, Double> vectorizer = new DummyVectorizer<Integer>(1, 2).labeled(0);
 
         DatasetBuilder<Integer, Vector> datasetBuilder = new LocalDatasetBuilder<>(data, parts);
 
@@ -65,7 +65,7 @@ public class EncoderTrainerTest extends TrainerTest {
             vectorizer
         );
 
-        assertArrayEquals(new double[]{0.0, 2.0}, preprocessor.apply(7, new DenseVector(new Serializable[]{"Monday", "September"})).features().asArray(), 1e-8);
+        assertArrayEquals(new double[]{0.0, 2.0}, preprocessor.apply(7, new DenseVector(new Serializable[]{7.0, "Monday", "September"})).features().asArray(), 1e-8);
     }
 
     /** Tests {@code fit()} method. */
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/selection/cv/CrossValidationTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/selection/cv/CrossValidationTest.java
index b161e58..9b45da8 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/selection/cv/CrossValidationTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/selection/cv/CrossValidationTest.java
@@ -21,6 +21,14 @@ import java.util.HashMap;
 import java.util.Map;
 import org.apache.ignite.ml.dataset.feature.extractor.Vectorizer;
 import org.apache.ignite.ml.dataset.feature.extractor.impl.DoubleArrayVectorizer;
+import org.apache.ignite.ml.nn.UpdatesStrategy;
+import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDParameterUpdate;
+import org.apache.ignite.ml.optimization.updatecalculators.SimpleGDUpdateCalculator;
+import org.apache.ignite.ml.pipeline.Pipeline;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionModel;
+import org.apache.ignite.ml.regressions.logistic.LogisticRegressionSGDTrainer;
+import org.apache.ignite.ml.selection.paramgrid.ParamGrid;
+import org.apache.ignite.ml.selection.paramgrid.RandomStrategy;
 import org.apache.ignite.ml.selection.scoring.metric.classification.Accuracy;
 import org.apache.ignite.ml.selection.scoring.metric.classification.BinaryClassificationMetricValues;
 import org.apache.ignite.ml.selection.scoring.metric.classification.BinaryClassificationMetrics;
@@ -28,8 +36,8 @@ import org.apache.ignite.ml.tree.DecisionTreeClassificationTrainer;
 import org.apache.ignite.ml.tree.DecisionTreeNode;
 import org.junit.Test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.apache.ignite.ml.common.TrainerTest.twoLinearlySeparableClasses;
+import static org.junit.Assert.*;
 
 /**
  * Tests for {@link CrossValidation}.
@@ -45,31 +53,23 @@ public class CrossValidationTest {
 
         DecisionTreeClassificationTrainer trainer = new DecisionTreeClassificationTrainer(1, 0);
 
-        CrossValidation<DecisionTreeNode, Double, Integer, double[]> scoreCalculator =
-            new CrossValidation<>();
+        DebugCrossValidation<DecisionTreeNode, Double, Integer, double[]> scoreCalculator =
+            new DebugCrossValidation<>();
 
         Vectorizer<Integer, double[], Integer, Double> vectorizer = new DoubleArrayVectorizer<Integer>().labeled(Vectorizer.LabelCoordinate.FIRST);
 
         int folds = 4;
 
-        verifyScores(folds, scoreCalculator.score(
-            trainer,
-            new Accuracy<>(),
-            data,
-            1,
-            vectorizer,
-            folds
-        ));
-
-        verifyScores(folds, scoreCalculator.score(
-            trainer,
-            new Accuracy<>(),
-            data,
-            (e1, e2) -> true,
-            1,
-            vectorizer,
-            folds
-        ));
+        scoreCalculator
+            .withUpstreamMap(data)
+            .withAmountOfParts(1)
+            .withTrainer(trainer)
+            .withMetric(new Accuracy<>())
+            .withPreprocessor(vectorizer)
+            .withAmountOfFolds(folds)
+            .isRunningOnPipeline(false);
+
+        verifyScores(folds, scoreCalculator.scoreByFolds());
     }
 
     /** */
@@ -84,32 +84,223 @@ public class CrossValidationTest {
 
         DecisionTreeClassificationTrainer trainer = new DecisionTreeClassificationTrainer(1, 0);
 
-        CrossValidation<DecisionTreeNode, Double, Integer, double[]> scoreCalculator =
-            new CrossValidation<>();
+        DebugCrossValidation<DecisionTreeNode, Double, Integer, double[]> scoreCalculator =
+            new DebugCrossValidation<>();
 
         int folds = 4;
 
         BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
             .withMetric(BinaryClassificationMetricValues::accuracy);
 
-        verifyScores(folds, scoreCalculator.score(
-            trainer,
-            metrics,
-            data,
-            1,
-            vectorizer,
-            folds
-        ));
-
-        verifyScores(folds, scoreCalculator.score(
-            trainer,
-            new Accuracy<>(),
-            data,
-            (e1, e2) -> true,
-            1,
-            vectorizer,
-            folds
-        ));
+        scoreCalculator
+            .withUpstreamMap(data)
+            .withAmountOfParts(1)
+            .withTrainer(trainer)
+            .withMetric(metrics)
+            .withPreprocessor(vectorizer)
+            .withAmountOfFolds(folds)
+            .isRunningOnPipeline(false);
+
+        verifyScores(folds, scoreCalculator.scoreByFolds());
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testBasicFunctionality() {
+        Map<Integer, double[]> data = new HashMap<>();
+
+        for (int i = 0; i < twoLinearlySeparableClasses.length; i++)
+            data.put(i, twoLinearlySeparableClasses[i]);
+
+        LogisticRegressionSGDTrainer trainer = new LogisticRegressionSGDTrainer()
+            .withUpdatesStgy(new UpdatesStrategy<>(new SimpleGDUpdateCalculator(0.2),
+                SimpleGDParameterUpdate.SUM_LOCAL, SimpleGDParameterUpdate.AVG))
+            .withMaxIterations(100000)
+            .withLocIterations(100)
+            .withBatchSize(14)
+            .withSeed(123L);
+
+        Vectorizer<Integer, double[], Integer, Double> vectorizer = new DoubleArrayVectorizer<Integer>().labeled(Vectorizer.LabelCoordinate.FIRST);
+
+        DebugCrossValidation<LogisticRegressionModel, Double, Integer, double[]> scoreCalculator =
+            new DebugCrossValidation<>();
+
+        int folds = 4;
+
+        BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
+            .withMetric(BinaryClassificationMetricValues::accuracy);
+
+        scoreCalculator
+            .withUpstreamMap(data)
+            .withAmountOfParts(1)
+            .withTrainer(trainer)
+            .withMetric(metrics)
+            .withPreprocessor(vectorizer)
+            .withAmountOfFolds(folds)
+            .isRunningOnPipeline(false);
+
+        double[] scores = scoreCalculator.scoreByFolds();
+
+        assertEquals(0.8389830508474576, scores[0], 1e-6);
+        assertEquals(0.9402985074626866, scores[1], 1e-6);
+        assertEquals(0.8809523809523809, scores[2], 1e-6);
+        assertEquals(0.9921259842519685, scores[3], 1e-6);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testGridSearch() {
+        Map<Integer, double[]> data = new HashMap<>();
+
+        for (int i = 0; i < twoLinearlySeparableClasses.length; i++)
+            data.put(i, twoLinearlySeparableClasses[i]);
+
+        LogisticRegressionSGDTrainer trainer = new LogisticRegressionSGDTrainer()
+            .withUpdatesStgy(new UpdatesStrategy<>(new SimpleGDUpdateCalculator(0.2),
+                SimpleGDParameterUpdate.SUM_LOCAL, SimpleGDParameterUpdate.AVG))
+            .withMaxIterations(100000)
+            .withLocIterations(100)
+            .withBatchSize(14)
+            .withSeed(123L);
+
+        Vectorizer<Integer, double[], Integer, Double> vectorizer = new DoubleArrayVectorizer<Integer>().labeled(Vectorizer.LabelCoordinate.FIRST);
+
+        BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
+            .withMetric(BinaryClassificationMetricValues::accuracy);
+
+        ParamGrid paramGrid = new ParamGrid()
+            .addHyperParam("maxIterations", trainer::withMaxIterations, new Double[]{10.0, 100.0, 1000.0, 10000.0})
+            .addHyperParam("locIterations", trainer::withLocIterations, new Double[]{10.0, 100.0, 1000.0, 10000.0})
+            .addHyperParam("batchSize", trainer::withBatchSize, new Double[]{1.0, 2.0, 4.0, 8.0, 16.0});
+
+        DebugCrossValidation<LogisticRegressionModel, Double, Integer, double[]> scoreCalculator =
+            (DebugCrossValidation<LogisticRegressionModel, Double, Integer, double[]>) new DebugCrossValidation<LogisticRegressionModel, Double, Integer, double[]>()
+                .withUpstreamMap(data)
+                .withAmountOfParts(1)
+                .withTrainer(trainer)
+                .withMetric(metrics)
+                .withPreprocessor(vectorizer)
+                .withAmountOfFolds(4)
+                .isRunningOnPipeline(false)
+                .withParamGrid(paramGrid);
+
+        CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
+
+
+        assertArrayEquals(crossValidationRes.getBestScore(), new double[]{0.9745762711864406, 1.0, 0.8968253968253969, 0.8661417322834646}, 1e-6);
+        assertEquals(crossValidationRes.getBestAvgScore(), 0.9343858500738256, 1e-6);
+        assertEquals(crossValidationRes.getScoringBoard().size(), 80);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testRandomSearch() {
+        Map<Integer, double[]> data = new HashMap<>();
+
+        for (int i = 0; i < twoLinearlySeparableClasses.length; i++)
+            data.put(i, twoLinearlySeparableClasses[i]);
+
+        LogisticRegressionSGDTrainer trainer = new LogisticRegressionSGDTrainer()
+            .withUpdatesStgy(new UpdatesStrategy<>(new SimpleGDUpdateCalculator(0.2),
+                SimpleGDParameterUpdate.SUM_LOCAL, SimpleGDParameterUpdate.AVG))
+            .withMaxIterations(100000)
+            .withLocIterations(100)
+            .withBatchSize(14)
+            .withSeed(123L);
+
+        Vectorizer<Integer, double[], Integer, Double> vectorizer = new DoubleArrayVectorizer<Integer>().labeled(Vectorizer.LabelCoordinate.FIRST);
+
+        BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
+            .withMetric(BinaryClassificationMetricValues::accuracy);
+
+        ParamGrid paramGrid = new ParamGrid()
+            .withParameterSearchStrategy(
+                new RandomStrategy()
+                    .withMaxTries(10)
+                    .withSeed(1234L)
+                    .withSatisfactoryFitness(0.9)
+            )
+            .addHyperParam("maxIterations", trainer::withMaxIterations, new Double[]{10.0, 100.0, 1000.0, 10000.0})
+            .addHyperParam("locIterations", trainer::withLocIterations, new Double[]{10.0, 100.0, 1000.0, 10000.0})
+            .addHyperParam("batchSize", trainer::withBatchSize, new Double[]{1.0, 2.0, 4.0, 8.0, 16.0});
+
+        DebugCrossValidation<LogisticRegressionModel, Double, Integer, double[]> scoreCalculator =
+            (DebugCrossValidation<LogisticRegressionModel, Double, Integer, double[]>) new DebugCrossValidation<LogisticRegressionModel, Double, Integer, double[]>()
+                .withUpstreamMap(data)
+                .withAmountOfParts(1)
+                .withTrainer(trainer)
+                .withMetric(metrics)
+                .withPreprocessor(vectorizer)
+                .withAmountOfFolds(4)
+                .isRunningOnPipeline(false)
+                .withParamGrid(paramGrid);
+
+        CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
+
+        assertEquals(crossValidationRes.getBestAvgScore(), 0.9343858500738256, 1e-6);
+        assertEquals(crossValidationRes.getScoringBoard().size(), 10);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testRandomSearchWithPipeline() {
+        Map<Integer, double[]> data = new HashMap<>();
+
+        for (int i = 0; i < twoLinearlySeparableClasses.length; i++)
+            data.put(i, twoLinearlySeparableClasses[i]);
+
+        LogisticRegressionSGDTrainer trainer = new LogisticRegressionSGDTrainer()
+            .withUpdatesStgy(new UpdatesStrategy<>(new SimpleGDUpdateCalculator(0.2),
+                SimpleGDParameterUpdate.SUM_LOCAL, SimpleGDParameterUpdate.AVG))
+            .withMaxIterations(100000)
+            .withLocIterations(100)
+            .withBatchSize(14)
+            .withSeed(123L);
+
+        Vectorizer<Integer, double[], Integer, Double> vectorizer = new DoubleArrayVectorizer<Integer>().labeled(Vectorizer.LabelCoordinate.FIRST);
+
+        BinaryClassificationMetrics metrics = (BinaryClassificationMetrics) new BinaryClassificationMetrics()
+            .withMetric(BinaryClassificationMetricValues::accuracy);
+
+        ParamGrid paramGrid = new ParamGrid()
+            .withParameterSearchStrategy(
+                new RandomStrategy()
+                    .withMaxTries(10)
+                    .withSeed(1234L)
+                    .withSatisfactoryFitness(0.9)
+            )
+            .addHyperParam("maxIterations", trainer::withMaxIterations, new Double[]{10.0, 100.0, 1000.0, 10000.0})
+            .addHyperParam("locIterations", trainer::withLocIterations, new Double[]{10.0, 100.0, 1000.0, 10000.0})
+            .addHyperParam("batchSize", trainer::withBatchSize, new Double[]{1.0, 2.0, 4.0, 8.0, 16.0});
+
+
+        Pipeline<Integer, double[], Integer, Double> pipeline = new Pipeline<Integer, double[], Integer, Double>()
+            .addVectorizer(vectorizer)
+            .addTrainer(trainer);
+
+        DebugCrossValidation<LogisticRegressionModel, Double, Integer, double[]> scoreCalculator =
+            (DebugCrossValidation<LogisticRegressionModel, Double, Integer, double[]>) new DebugCrossValidation<LogisticRegressionModel, Double, Integer, double[]>()
+                .withUpstreamMap(data)
+                .withAmountOfParts(1)
+                .withPipeline(pipeline)
+                .withMetric(metrics)
+                .withPreprocessor(vectorizer)
+                .withAmountOfFolds(4)
+                .isRunningOnPipeline(true)
+                .withParamGrid(paramGrid);
+
+        CrossValidationResult crossValidationRes = scoreCalculator.tuneHyperParamterers();
+
+        assertEquals(crossValidationRes.getBestAvgScore(), 0.9343858500738256, 1e-6);
+        assertEquals(crossValidationRes.getScoringBoard().size(), 10);
     }
 
     /** */
@@ -124,19 +315,23 @@ public class CrossValidationTest {
 
         DecisionTreeClassificationTrainer trainer = new DecisionTreeClassificationTrainer(1, 0);
 
-        CrossValidation<DecisionTreeNode, Double, Integer, double[]> scoreCalculator =
-            new CrossValidation<>();
+        DebugCrossValidation<DecisionTreeNode, Double, Integer, double[]> scoreCalculator =
+            new DebugCrossValidation<>();
 
         int folds = 4;
 
-        double[] scores = scoreCalculator.score(
-            trainer,
-            new Accuracy<>(),
-            data,
-            1,
-            vectorizer,
-            folds
-        );
+        scoreCalculator
+            .withUpstreamMap(data)
+            .withAmountOfParts(1)
+            .withTrainer(trainer)
+            .withMetric(new Accuracy<>())
+
+            .withPreprocessor(vectorizer)
+            .withAmountOfFolds(folds)
+            .isRunningOnPipeline(false);
+
+
+        double[] scores = scoreCalculator.scoreByFolds();
 
         assertEquals(folds, scores.length);
 
@@ -152,3 +347,7 @@ public class CrossValidationTest {
             assertEquals(1, scores[i], 1e-1);
     }
 }
+
+
+
+
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java b/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
index 201ab5d..08dbf13 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/util/UtilTestSuite.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.ml.util;
 
+import org.apache.ignite.ml.util.genetic.GeneticAlgorithmTest;
+import org.apache.ignite.ml.util.genetic.PopulationTest;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 
@@ -25,7 +27,9 @@ import org.junit.runners.Suite;
  */
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-    LRUCacheTest.class
+    LRUCacheTest.class,
+    GeneticAlgorithmTest.class,
+    PopulationTest.class
 })
 public class UtilTestSuite {
 }
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/util/genetic/GeneticAlgorithmTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/util/genetic/GeneticAlgorithmTest.java
new file mode 100644
index 0000000..75324e0
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/util/genetic/GeneticAlgorithmTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ml.util.genetic;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for {@link GeneticAlgorithm}.
+ */
+public class GeneticAlgorithmTest {
+    /** Amount of genes in chromosome. */
+    public static final int AMOUNT_OF_GENES_IN_CHROMOSOME = 8;
+
+    /** Precision. */
+    private static final double PRECISION = 0.00000001;
+
+    /** Fitness function. */
+    Function<Chromosome, Double> fitnessFunction = (Chromosome ch) -> {
+        double fitness = 0;
+        for (int i = 0; i < ch.size(); i += 2) fitness += ch.getGene(i);
+        return fitness;
+    };
+
+    /** Random. */
+    Random rnd = new Random(1234L);
+
+    /** Genetic algorithm instance. */
+    private GeneticAlgorithm ga;
+
+    /**
+     *
+     */
+    @Before
+    public void setUp() {
+        List<Double[]> rawData = new ArrayList<>();
+        for (int i = 0; i < 100; i++) {
+            Double[] chromosomeData = new Double[AMOUNT_OF_GENES_IN_CHROMOSOME];
+            for (int j = 0; j < AMOUNT_OF_GENES_IN_CHROMOSOME; j++)
+                chromosomeData[j] = rnd.nextDouble();
+            rawData.add(i, chromosomeData);
+        }
+
+
+        ga = new GeneticAlgorithm(rawData);
+        BiFunction<Integer, Double, Double> mutator = (integer, aDouble) -> rnd.nextDouble() > 0.5 ? aDouble + (rnd.nextDouble() / 100) : aDouble - (rnd.nextDouble() / 100);
+
+        ga.withFitnessFunction(fitnessFunction)
+            .withMutationOperator(mutator)
+            .withAmountOfEliteChromosomes(10)
+            .withCrossingoverProbability(0.01)
+            .withCrossoverStgy(CrossoverStrategy.ONE_POINT)
+            .withAmountOfGenerations(100)
+            .withSelectionStgy(SelectionStrategy.ROULETTE_WHEEL)
+            .withMutationProbability(0.05);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void runGeneticAlgorithm() {
+        ga.run();
+        double[] expBestSolution = {0.9227093559081438, 0.8716316379636383, 0.9393034992555963, 0.9264946442527818,
+            0.8030164650964057, 0.41871505180713764, 1.0294056830181408, 0.5760945730781087};
+        Assert.assertArrayEquals(ga.getTheBestSolution(), expBestSolution, PRECISION);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void runParallelGeneticAlgorithm() {
+        ga.run();
+        double[] expBestSolution = {0.9227093559081438, 0.8716316379636383, 0.9393034992555963, 0.9264946442527818,
+            0.8030164650964057, 0.41871505180713764, 1.0294056830181408, 0.5760945730781087};
+        Assert.assertArrayEquals(ga.getTheBestSolution(), expBestSolution, PRECISION);
+    }
+}
\ No newline at end of file
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/util/genetic/PopulationTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/util/genetic/PopulationTest.java
new file mode 100644
index 0000000..d5e20ce
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/util/genetic/PopulationTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.ml.util.genetic;
+
+import java.util.function.Function;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for {@link Population}.
+ */
+public class PopulationTest {
+    /** Amount of the best chromosomes. */
+    public static final int K = 10;
+
+    /** Test population. */
+    Population population;
+
+    /** Precision. */
+    private static final double PRECISION = 0.00000001;
+
+    /** Fitness function. */
+    Function<Chromosome, Double> fitnessFunction = (Chromosome ch) -> ch.getGene(0) + ch.getGene(1);
+
+    /**
+     *
+     */
+    @Before
+    public void setUp() {
+        population = new Population(100);
+        Double[] chromosomeData = new Double[2];
+        for (int i = 0; i < population.size(); i++) {
+            chromosomeData[0] = (double) i;
+            chromosomeData[1] = (double) i;
+            population.setChromosome(i, new Chromosome(chromosomeData));
+        }
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void calculateFitnessForChromosome() {
+        population.calculateFitnessForChromosome(0, fitnessFunction);
+        Assert.assertEquals(population.getChromosome(0).getFitness(), 0, PRECISION);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void calculateFitnessForAll() {
+        population.calculateFitnessForAll(fitnessFunction);
+        Assert.assertEquals(population.getChromosome(0).getFitness(), 0, PRECISION);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void selectBestKChromosomeWithoutFitnessCalculation() {
+        Assert.assertNull(population.selectBestKChromosome(K));
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void selectBestKChromosomeWithPartiallyFitnessCalculation() {
+        population.calculateFitnessForChromosome(0, fitnessFunction);
+        population.calculateFitnessForChromosome(1, fitnessFunction);
+        Assert.assertNull(population.selectBestKChromosome(K));
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void selectBestKChromosome() {
+        population.calculateFitnessForAll(fitnessFunction);
+        Chromosome[] res = population.selectBestKChromosome(K);
+        Assert.assertEquals(res[0].getFitness(), 180, PRECISION);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void getTotalFitness() {
+        double res = population.getTotalFitness();
+        Assert.assertEquals(res, Double.NaN, PRECISION);
+
+        population.calculateFitnessForAll(fitnessFunction);
+        res = population.getTotalFitness();
+        Assert.assertEquals(res, 9900.0, PRECISION);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void getAverageFitness() {
+        double res = population.getAverageFitness();
+        Assert.assertEquals(res, Double.NaN, PRECISION);
+
+        population.calculateFitnessForAll(fitnessFunction);
+        res = population.getAverageFitness();
+        Assert.assertEquals(res, 99.0, PRECISION);
+    }
+}
\ No newline at end of file