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

[1/2] ignite git commit: IGNITE-5278: BLAS implemented.

Repository: ignite
Updated Branches:
  refs/heads/master 131847203 -> de259fffb


http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/test/java/org/apache/ignite/ml/math/BlasTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/BlasTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/BlasTest.java
new file mode 100644
index 0000000..00bce47
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/BlasTest.java
@@ -0,0 +1,357 @@
+/*
+ * 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.math;
+
+import java.util.function.BiPredicate;
+import org.apache.ignite.ml.math.impls.matrix.DenseLocalOnHeapMatrix;
+import org.apache.ignite.ml.math.impls.matrix.SparseLocalOnHeapMatrix;
+import org.apache.ignite.ml.math.impls.vector.DenseLocalOnHeapVector;
+import org.apache.ignite.ml.math.impls.vector.SparseLocalVector;
+import org.apache.ignite.ml.math.util.MatrixUtil;
+import org.junit.Assert;
+import org.junit.Test;
+
+/** Tests for BLAS operations (all operations are only available for local matrices and vectors). */
+public class BlasTest {
+    /** Test 'axpy' operation for two array-based vectors. */
+    @Test
+    public void testAxpyArrayArray() {
+        Vector y = new DenseLocalOnHeapVector(new double[] {1.0, 2.0});
+        double a = 2.0;
+        Vector x = new DenseLocalOnHeapVector(new double[] {1.0, 2.0});
+
+        Vector exp = x.times(a).plus(y);
+        Blas.axpy(a, x, y);
+
+        Assert.assertEquals(y, exp);
+    }
+
+    /** Test 'axpy' operation for sparse vector and array-based vector. */
+    @Test
+    public void testAxpySparseArray() {
+        DenseLocalOnHeapVector y = new DenseLocalOnHeapVector(new double[] {1.0, 2.0});
+        double a = 2.0;
+        SparseLocalVector x = sparseFromArray(new double[] {1.0, 2.0});
+
+        SparseLocalVector exp = (SparseLocalVector)x.times(a).plus(y);
+        Blas.axpy(a, x, y);
+
+        Assert.assertTrue(elementsEqual(exp, y));
+    }
+
+    /** Test 'dot' operation. */
+    @Test
+    public void testDot() {
+        DenseLocalOnHeapVector v1 = new DenseLocalOnHeapVector(new double[] {1.0, 1.0});
+        DenseLocalOnHeapVector v2 = new DenseLocalOnHeapVector(new double[] {2.0, 2.0});
+
+        Assert.assertEquals(Blas.dot(v1, v2), v1.dot(v2), 0.0);
+    }
+
+    /** Test 'scal' operation for dense matrix. */
+    @Test
+    public void testScalDense() {
+        double[] data = new double[] {1.0, 1.0};
+        double alpha = 2.0;
+
+        DenseLocalOnHeapVector v = new DenseLocalOnHeapVector(data);
+        Vector exp = new DenseLocalOnHeapVector(data, true).times(alpha);
+        Blas.scal(alpha, v);
+
+        Assert.assertEquals(v, exp);
+    }
+
+    /** Test 'scal' operation for sparse matrix. */
+    @Test
+    public void testScalSparse() {
+        double[] data = new double[] {1.0, 1.0};
+        double alpha = 2.0;
+
+        SparseLocalVector v = sparseFromArray(data);
+        Vector exp = sparseFromArray(data).times(alpha);
+
+        Blas.scal(alpha, v);
+
+        Assert.assertEquals(v, exp);
+    }
+
+    /** Test 'spr' operation for dense vector v and dense matrix A. */
+    @Test
+    public void testSprDenseDense() {
+        double alpha = 3.0;
+
+        DenseLocalOnHeapVector v = new DenseLocalOnHeapVector(new double[] {1.0, 2.0});
+        DenseLocalOnHeapVector u = new DenseLocalOnHeapVector(new double[] {3.0, 13.0, 20.0, 0.0});
+
+        // m is alpha * v * v^t
+        DenseLocalOnHeapMatrix m = (DenseLocalOnHeapMatrix)new DenseLocalOnHeapMatrix(new double[][] {{1.0, 0.0},
+            {2.0, 4.0}}, StorageConstants.COLUMN_STORAGE_MODE).times(alpha);
+        DenseLocalOnHeapMatrix a = new DenseLocalOnHeapMatrix(new double[][] {{3.0, 0.0}, {13.0, 20.0}},
+            StorageConstants.COLUMN_STORAGE_MODE);
+
+        //m := alpha * v * v.t + A
+        Blas.spr(alpha, v, u);
+
+        DenseLocalOnHeapMatrix mu = fromVector(u, a.rowSize(), StorageConstants.COLUMN_STORAGE_MODE, (i, j) -> i >= j);
+        Assert.assertEquals(m.plus(a), mu);
+    }
+
+    /** Test 'spr' operation for sparse vector v (sparse in representation, dense in fact) and dense matrix A. */
+    @Test
+    public void testSprSparseDense1() {
+        double alpha = 3.0;
+
+        SparseLocalVector v = sparseFromArray(new double[] {1.0, 2.0});
+        DenseLocalOnHeapVector u = new DenseLocalOnHeapVector(new double[] {3.0, 13.0, 20.0, 0.0});
+
+        DenseLocalOnHeapMatrix a = new DenseLocalOnHeapMatrix(new double[][] {{3.0, 0.0}, {13.0, 20.0}},
+            StorageConstants.COLUMN_STORAGE_MODE);
+        DenseLocalOnHeapMatrix exp = (DenseLocalOnHeapMatrix)new DenseLocalOnHeapMatrix(new double[][] {{1.0, 0.0},
+            {2.0, 4.0}}, StorageConstants.COLUMN_STORAGE_MODE).times(alpha).plus(a);
+
+        //m := alpha * v * v.t + A
+        Blas.spr(alpha, v, u);
+        DenseLocalOnHeapMatrix mu = fromVector(u, a.rowSize(), StorageConstants.COLUMN_STORAGE_MODE, (i, j) -> i >= j);
+        Assert.assertEquals(exp, mu);
+    }
+
+    /** Test 'spr' operation for sparse vector v (sparse in representation, sparse in fact) and dense matrix A. */
+    @Test
+    public void testSprSparseDense2() {
+        double alpha = 3.0;
+
+        SparseLocalVector v = new SparseLocalVector(2, StorageConstants.RANDOM_ACCESS_MODE);
+        v.set(0, 1);
+
+        DenseLocalOnHeapVector u = new DenseLocalOnHeapVector(new double[] {3.0, 13.0, 20.0, 0.0});
+
+        // m is alpha * v * v^t
+        DenseLocalOnHeapMatrix m = (DenseLocalOnHeapMatrix)new DenseLocalOnHeapMatrix(new double[][] {{1.0, 0.0},
+            {0.0, 0.0}}, StorageConstants.COLUMN_STORAGE_MODE).times(alpha);
+        DenseLocalOnHeapMatrix a = new DenseLocalOnHeapMatrix(new double[][] {{3.0, 0.0}, {13.0, 20.0}},
+            StorageConstants.COLUMN_STORAGE_MODE);
+
+        //m := alpha * v * v.t + A
+        Blas.spr(alpha, v, u);
+        DenseLocalOnHeapMatrix mu = fromVector(u, a.rowSize(), StorageConstants.COLUMN_STORAGE_MODE, (i, j) -> i >= j);
+        Assert.assertEquals(m.plus(a), mu);
+    }
+
+    /** Tests 'syr' operation for dense vector x and dense matrix A. */
+    @Test
+    public void testSyrDenseDense() {
+        double alpha = 2.0;
+        DenseLocalOnHeapVector x = new DenseLocalOnHeapVector(new double[] {1.0, 2.0});
+        DenseLocalOnHeapMatrix a = new DenseLocalOnHeapMatrix(new double[][] {{10.0, 20.0}, {20.0, 10.0}});
+
+        // alpha * x * x^T + A
+        DenseLocalOnHeapMatrix exp = (DenseLocalOnHeapMatrix)new DenseLocalOnHeapMatrix(new double[][] {{1.0, 2.0},
+            {2.0, 4.0}}).times(alpha).plus(a);
+
+        Blas.syr(alpha, x, a);
+
+        Assert.assertEquals(exp, a);
+    }
+
+    /** Tests 'gemm' operation for dense matrix A, dense matrix B and dense matrix C. */
+    @Test
+    public void testGemmDenseDenseDense() {
+        // C := alpha * A * B + beta * C
+        double alpha = 2.0;
+        DenseLocalOnHeapMatrix a = new DenseLocalOnHeapMatrix(new double[][] {{10.0, 11.0}, {0.0, 1.0}});
+        DenseLocalOnHeapMatrix b = new DenseLocalOnHeapMatrix(new double[][] {{1.0, 0.0}, {0.0, 1.0}});
+        double beta = 3.0;
+        DenseLocalOnHeapMatrix c = new DenseLocalOnHeapMatrix(new double[][] {{1.0, 2.0}, {2.0, 3.0}});
+
+        DenseLocalOnHeapMatrix exp = (DenseLocalOnHeapMatrix)a.times(b).times(alpha).plus(c.times(beta));
+
+        Blas.gemm(alpha, a, b, beta, c);
+        Assert.assertEquals(exp, c);
+    }
+
+    /** Tests 'gemm' operation for sparse matrix A, dense matrix B and dense matrix C. */
+    @Test
+    public void testGemmSparseDenseDense() {
+        // C := alpha * A * B + beta * C
+        double alpha = 2.0;
+        SparseLocalOnHeapMatrix a = sparseFromArray(new double[][] {{10.0, 11.0}, {0.0, 1.0}}, 2);
+        DenseLocalOnHeapMatrix b = new DenseLocalOnHeapMatrix(new double[][] {{1.0, 0.0}, {0.0, 1.0}});
+        double beta = 3.0;
+        DenseLocalOnHeapMatrix c = new DenseLocalOnHeapMatrix(new double[][] {{1.0, 2.0}, {2.0, 3.0}});
+
+        DenseLocalOnHeapMatrix exp = MatrixUtil.asDense((SparseLocalOnHeapMatrix)a.times(b).times(alpha).plus(c.times(beta)),
+            StorageConstants.ROW_STORAGE_MODE);
+
+        Blas.gemm(alpha, a, b, beta, c);
+
+        Assert.assertEquals(exp, c);
+    }
+
+    /** Tests 'gemv' operation for dense matrix A, dense vector x and dense vector y. */
+    @Test
+    public void testGemvSparseDenseDense() {
+        // y := alpha * A * x + beta * y
+        double alpha = 3.0;
+        SparseLocalOnHeapMatrix a = sparseFromArray(new double[][] {{10.0, 11.0}, {0.0, 1.0}}, 2);
+        DenseLocalOnHeapVector x = new DenseLocalOnHeapVector(new double[] {1.0, 2.0});
+        double beta = 2.0;
+        DenseLocalOnHeapVector y = new DenseLocalOnHeapVector(new double[] {3.0, 4.0});
+
+        DenseLocalOnHeapVector exp = (DenseLocalOnHeapVector)y.times(beta).plus(a.times(x).times(alpha));
+
+        Blas.gemv(alpha, a, x, beta, y);
+
+        Assert.assertEquals(exp, y);
+    }
+
+    /** Tests 'gemv' operation for dense matrix A, sparse vector x and dense vector y. */
+    @Test
+    public void testGemvDenseSparseDense() {
+        // y := alpha * A * x + beta * y
+        double alpha = 3.0;
+        SparseLocalOnHeapMatrix a = sparseFromArray(new double[][] {{10.0, 11.0}, {0.0, 1.0}}, 2);
+        SparseLocalVector x = sparseFromArray(new double[] {1.0, 2.0});
+        double beta = 2.0;
+        DenseLocalOnHeapVector y = new DenseLocalOnHeapVector(new double[] {3.0, 4.0});
+
+        DenseLocalOnHeapVector exp = (DenseLocalOnHeapVector)y.times(beta).plus(a.times(x).times(alpha));
+
+        Blas.gemv(alpha, a, x, beta, y);
+
+        Assert.assertEquals(exp, y);
+    }
+
+    /** Tests 'gemv' operation for sparse matrix A, sparse vector x and dense vector y. */
+    @Test
+    public void testGemvSparseSparseDense() {
+        // y := alpha * A * x + beta * y
+        double alpha = 3.0;
+        DenseLocalOnHeapMatrix a = new DenseLocalOnHeapMatrix(new double[][] {{10.0, 11.0}, {0.0, 1.0}}, 2);
+        SparseLocalVector x = sparseFromArray(new double[] {1.0, 2.0});
+        double beta = 2.0;
+        DenseLocalOnHeapVector y = new DenseLocalOnHeapVector(new double[] {3.0, 4.0});
+
+        DenseLocalOnHeapVector exp = (DenseLocalOnHeapVector)y.times(beta).plus(a.times(x).times(alpha));
+
+        Blas.gemv(alpha, a, x, beta, y);
+
+        Assert.assertEquals(exp, y);
+    }
+
+    /** Tests 'gemv' operation for dense matrix A, dense vector x and dense vector y. */
+    @Test
+    public void testGemvDenseDenseDense() {
+        // y := alpha * A * x + beta * y
+        double alpha = 3.0;
+        DenseLocalOnHeapMatrix a = new DenseLocalOnHeapMatrix(new double[][] {{10.0, 11.0}, {0.0, 1.0}}, 2);
+        DenseLocalOnHeapVector x = new DenseLocalOnHeapVector(new double[] {1.0, 2.0});
+        double beta = 2.0;
+        DenseLocalOnHeapVector y = new DenseLocalOnHeapVector(new double[] {3.0, 4.0});
+
+        DenseLocalOnHeapVector exp = (DenseLocalOnHeapVector)y.times(beta).plus(a.times(x).times(alpha));
+
+        Blas.gemv(alpha, a, x, beta, y);
+
+        Assert.assertEquals(exp, y);
+    }
+
+    /**
+     * Create a sparse vector from array.
+     *
+     * @param arr Array with vector elements.
+     * @return sparse local on-heap vector.
+     */
+    private static SparseLocalVector sparseFromArray(double[] arr) {
+        SparseLocalVector res = new SparseLocalVector(2, StorageConstants.RANDOM_ACCESS_MODE);
+
+        for (int i = 0; i < arr.length; i++)
+            res.setX(i, arr[i]);
+
+        return res;
+    }
+
+    /**
+     * Create a sparse matrix from array.
+     *
+     * @param arr Array with matrix elements.
+     * @param rows Number of rows in target matrix.
+     * @return sparse local on-heap matrix.
+     */
+    private static SparseLocalOnHeapMatrix sparseFromArray(double[][] arr, int rows) {
+        int cols = arr[0].length;
+        SparseLocalOnHeapMatrix res = new SparseLocalOnHeapMatrix(rows, cols);
+
+        for (int i = 0; i < rows; i++)
+            for (int j = 0; j < cols; j++)
+                res.set(i, j, arr[i][j]);
+
+        return res;
+    }
+
+    /**
+     * Checks if two vectors have equal elements.
+     *
+     * @param a Matrix a.
+     * @param b Vector b
+     * @return true if vectors are equal element-wise, false otherwise.
+     */
+    private static boolean elementsEqual(Vector a, Vector b) {
+        int n = b.size();
+
+        for (int i = 0; i < n; i++)
+            if (a.get(i) != b.get(i))
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Creates dense local on-heap matrix from vector v entities filtered by bipredicate p.
+     *
+     * @param v Vector with entities for matrix to be created.
+     * @param rows Rows number in the target matrix.
+     * @param acsMode column or row major mode.
+     * @param p bipredicate to filter entities by.
+     * @return dense local on-heap matrix.
+     */
+    private static DenseLocalOnHeapMatrix fromVector(DenseLocalOnHeapVector v, int rows, int acsMode,
+        BiPredicate<Integer, Integer> p) {
+        double[] data = v.getStorage().data();
+        int cols = data.length / rows;
+        double[] d = new double[data.length];
+
+        int iLim = acsMode == StorageConstants.ROW_STORAGE_MODE ? rows : cols;
+        int jLim = acsMode == StorageConstants.ROW_STORAGE_MODE ? cols : rows;
+
+        int shift = 0;
+
+        for (int i = 0; i < iLim; i++)
+            for (int j = 0; j < jLim; j++) {
+                int ind = i * jLim + j;
+
+                if (!p.test(i, j)) {
+                    shift++;
+                    d[ind] = 0.0;
+                    continue;
+                }
+                d[ind] = data[ind - shift];
+            }
+
+        return new DenseLocalOnHeapMatrix(d, rows, acsMode);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/test/java/org/apache/ignite/ml/math/MathImplMainTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/MathImplMainTestSuite.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/MathImplMainTestSuite.java
index 4d245b4..974b7bb 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/math/MathImplMainTestSuite.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/MathImplMainTestSuite.java
@@ -27,7 +27,8 @@ import org.junit.runners.Suite;
 @Suite.SuiteClasses({
     MathImplLocalTestSuite.class,
     MathImplDistributedTestSuite.class,
-    TracerTest.class
+    TracerTest.class,
+    BlasTest.class
 })
 public class MathImplMainTestSuite {
     // No-op.

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixViewConstructorTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixViewConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixViewConstructorTest.java
index 82564cb..3e9cdfe 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixViewConstructorTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixViewConstructorTest.java
@@ -108,7 +108,7 @@ public class MatrixViewConstructorTest {
             assertEquals(m.isDense(), delegateStorage.isDense());
             assertEquals(m.isArrayBased(), delegateStorage.isArrayBased());
 
-            assertArrayEquals(m.getStorage().data(), delegateStorage.data());
+            assertArrayEquals(m.getStorage().data(), delegateStorage.data(), 0.0);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixArrayStorageTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixArrayStorageTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixArrayStorageTest.java
index 569ed57..3395422 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixArrayStorageTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixArrayStorageTest.java
@@ -54,10 +54,10 @@ public class MatrixArrayStorageTest extends MatrixBaseStorageTest<ArrayMatrixSto
     /** */
     @Test
     public void data() throws Exception {
-        double[][] data = storage.data();
+        double[] data = storage.data();
         assertNotNull(MathTestConstants.NULL_VAL, data);
-        assertTrue(MathTestConstants.UNEXPECTED_VAL, data.length == MathTestConstants.STORAGE_SIZE);
-        assertTrue(MathTestConstants.UNEXPECTED_VAL, data[0].length == MathTestConstants.STORAGE_SIZE);
+        assertTrue(MathTestConstants.UNEXPECTED_VAL, data.length == MathTestConstants.STORAGE_SIZE *
+            MathTestConstants.STORAGE_SIZE);
     }
 
 }


[2/2] ignite git commit: IGNITE-5278: BLAS implemented.

Posted by is...@apache.org.
IGNITE-5278: BLAS implemented.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/de259fff
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/de259fff
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/de259fff

Branch: refs/heads/master
Commit: de259fffb7fa5c0f8f6f7eeb84b86f296fe3bde9
Parents: 1318472
Author: Yury Babak <yb...@gridgain.com>
Authored: Tue Jul 25 20:19:27 2017 +0300
Committer: Igor Sapego <is...@gridgain.com>
Committed: Tue Jul 25 20:19:27 2017 +0300

----------------------------------------------------------------------
 LICENSE                                         |   7 +
 .../ml/math/matrix/ExampleMatrixStorage.java    |   6 +-
 modules/ml/README.txt                           |   6 +
 modules/ml/licenses/bsd3.txt                    |  51 ++
 modules/ml/pom.xml                              |  22 +
 .../java/org/apache/ignite/ml/math/Blas.java    | 484 +++++++++++++++++++
 .../java/org/apache/ignite/ml/math/Matrix.java  |  31 ++
 .../apache/ignite/ml/math/MatrixStorage.java    |   2 +-
 .../apache/ignite/ml/math/OrderedMatrix.java    |  24 +
 .../java/org/apache/ignite/ml/math/Vector.java  |   8 +
 .../decompositions/CholeskyDecomposition.java   |  11 +-
 .../IgniteIntDoubleToDoubleBiFunction.java      |  27 ++
 .../functions/IgniteIntIntToIntBiFunction.java  |  27 ++
 .../ml/math/functions/IgniteTriFunction.java    |  35 ++
 .../ml/math/impls/matrix/AbstractMatrix.java    |  94 +++-
 .../impls/matrix/DenseLocalOnHeapMatrix.java    |  61 ++-
 .../impls/matrix/SparseLocalOnHeapMatrix.java   |  27 ++
 .../storage/matrix/ArrayMatrixStorage.java      |  78 ++-
 .../matrix/DenseOffHeapMatrixStorage.java       |   2 +-
 .../storage/matrix/MatrixDelegateStorage.java   |   2 +-
 .../matrix/SparseDistributedMatrixStorage.java  |   4 +-
 .../matrix/SparseLocalOnHeapMatrixStorage.java  |  18 +
 .../vector/SparseLocalOnHeapVectorStorage.java  |   6 +
 .../impls/vector/AbstractReadOnlyVector.java    |   6 +
 .../ml/math/impls/vector/AbstractVector.java    |   8 +
 .../ml/math/impls/vector/DelegatingVector.java  |   6 +
 .../ml/math/impls/vector/SparseLocalVector.java |  39 ++
 .../apache/ignite/ml/math/util/MatrixUtil.java  |  48 ++
 .../KMeansDistributedClustererTest.java         |  15 +-
 .../org/apache/ignite/ml/math/BlasTest.java     | 357 ++++++++++++++
 .../ignite/ml/math/MathImplMainTestSuite.java   |   3 +-
 .../impls/matrix/MatrixViewConstructorTest.java |   2 +-
 .../storage/matrix/MatrixArrayStorageTest.java  |   6 +-
 33 files changed, 1475 insertions(+), 48 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
index c971434..6e77825 100644
--- a/LICENSE
+++ b/LICENSE
@@ -220,6 +220,13 @@ This product bundles SnapTree, which is available under a
 https://github.com/nbronson/snaptree/blob/master/LICENSE.
 
 ==============================================================================
+For netlib-java:
+==============================================================================
+This product bundles netlib-java, which is available under a
+"3-clause BSD" license.  For details, see
+https://github.com/fommil/netlib-java/blob/master/LICENSE.txt.
+
+==============================================================================
 For JSR 166 classes in "org.jsr166" package
 ==============================================================================
 This product bundles JSR-166 classes which are donated to public domain.

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/examples/src/main/ml/org/apache/ignite/examples/ml/math/matrix/ExampleMatrixStorage.java
----------------------------------------------------------------------
diff --git a/examples/src/main/ml/org/apache/ignite/examples/ml/math/matrix/ExampleMatrixStorage.java b/examples/src/main/ml/org/apache/ignite/examples/ml/math/matrix/ExampleMatrixStorage.java
index 5dedfbf..1ccb2e2 100644
--- a/examples/src/main/ml/org/apache/ignite/examples/ml/math/matrix/ExampleMatrixStorage.java
+++ b/examples/src/main/ml/org/apache/ignite/examples/ml/math/matrix/ExampleMatrixStorage.java
@@ -23,7 +23,9 @@ import java.io.ObjectOutput;
 import java.util.Arrays;
 
 import org.apache.ignite.ml.math.MatrixStorage;
+import org.apache.ignite.ml.math.StorageConstants;
 import org.apache.ignite.ml.math.impls.storage.matrix.ArrayMatrixStorage;
+import org.apache.ignite.ml.math.util.MatrixUtil;
 
 /**
  * Example matrix storage implementation, modeled after {@link ArrayMatrixStorage}.
@@ -117,8 +119,8 @@ class ExampleMatrixStorage implements MatrixStorage {
     }
 
     /** {@inheritDoc} */
-    @Override public double[][] data() {
-        return data;
+    @Override public double[] data() {
+        return MatrixUtil.flatten(data, StorageConstants.ROW_STORAGE_MODE);
     }
 
     /** {@inheritDoc */

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/README.txt
----------------------------------------------------------------------
diff --git a/modules/ml/README.txt b/modules/ml/README.txt
index e0cc093..e85b7a0 100644
--- a/modules/ml/README.txt
+++ b/modules/ml/README.txt
@@ -12,4 +12,10 @@ Based on ideas from Apache Mahout.
 Run from project root:
 mvn clean package -Pml -DskipTests -pl modules/ml -am
 
+Apache binary releases cannot include LGPL dependencies. If you would like to activate native BLAS optimizations
+into your build, you should download the source release
+from Ignite website and do the build with the following maven command:
+
+mvn clean package -Pml,lgpl -DskipTests -pl modules/ml -am
+
 Find generated jars in target folder.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/licenses/bsd3.txt
----------------------------------------------------------------------
diff --git a/modules/ml/licenses/bsd3.txt b/modules/ml/licenses/bsd3.txt
new file mode 100644
index 0000000..d6b30c1
--- /dev/null
+++ b/modules/ml/licenses/bsd3.txt
@@ -0,0 +1,51 @@
+This product binaries redistribute netlib-java which is available under the following license:
+
+Copyright (c) 2013 Samuel Halliday
+Copyright (c) 1992-2011 The University of Tennessee and The University
+                        of Tennessee Research Foundation.  All rights
+                        reserved.
+Copyright (c) 2000-2011 The University of California Berkeley. All
+                        rights reserved.
+Copyright (c) 2006-2011 The University of Colorado Denver.  All rights
+                        reserved.
+
+$COPYRIGHT$
+
+Additional copyrights may follow
+
+$HEADER$
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+- Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer listed
+  in this license in the documentation and/or other materials
+  provided with the distribution.
+
+- Neither the name of the copyright holders nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+The copyright holders provide no reassurances that the source code
+provided does not infringe any patent, copyright, or any other
+intellectual property rights of third parties.  The copyright holders
+disclaim any liability to any recipient for claims brought against
+recipient by any third party for infringement of that parties
+intellectual property rights.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/pom.xml
----------------------------------------------------------------------
diff --git a/modules/ml/pom.xml b/modules/ml/pom.xml
index d619719..478d8c4 100644
--- a/modules/ml/pom.xml
+++ b/modules/ml/pom.xml
@@ -36,6 +36,7 @@
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <netlibjava.version>1.1.2</netlibjava.version>
     </properties>
 
     <dependencies>
@@ -88,6 +89,13 @@
         </dependency>
 
         <dependency>
+            <groupId>com.github.fommil.netlib</groupId>
+            <artifactId>core</artifactId>
+            <version>${netlibjava.version}</version>
+            <type>pom</type>
+        </dependency>
+
+        <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-rng-core</artifactId>
             <version>1.0</version>
@@ -101,6 +109,20 @@
 
     </dependencies>
 
+    <profiles>
+        <profile>
+            <id>lgpl</id>
+
+            <dependencies>
+                <dependency>
+                    <groupId>com.github.fommil.netlib</groupId>
+                    <artifactId>all</artifactId>
+                    <version>${netlibjava.version}</version>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
+
     <build>
         <plugins>
             <plugin>

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/Blas.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/Blas.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/Blas.java
new file mode 100644
index 0000000..57f994e
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/Blas.java
@@ -0,0 +1,484 @@
+/*
+ * 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.math;
+
+import com.github.fommil.netlib.BLAS;
+import com.github.fommil.netlib.F2jBLAS;
+import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
+import it.unimi.dsi.fastutil.ints.IntIterator;
+import it.unimi.dsi.fastutil.ints.IntSet;
+import java.util.Set;
+import org.apache.ignite.ml.math.exceptions.CardinalityException;
+import org.apache.ignite.ml.math.exceptions.MathIllegalArgumentException;
+import org.apache.ignite.ml.math.exceptions.NonSquareMatrixException;
+import org.apache.ignite.ml.math.impls.matrix.DenseLocalOnHeapMatrix;
+import org.apache.ignite.ml.math.impls.matrix.SparseLocalOnHeapMatrix;
+import org.apache.ignite.ml.math.impls.vector.DenseLocalOnHeapVector;
+import org.apache.ignite.ml.math.impls.vector.SparseLocalVector;
+
+/**
+ * Useful subset of BLAS operations.
+ * This class is based on 'BLAS' class from Apache Spark MLlib.
+ */
+public class Blas {
+    /** F2J implementation of BLAS. */
+    transient static private BLAS f2jBlas = new F2jBLAS();
+
+    /** Native implementation of BLAS. F2J implementation will be used as fallback if no native implementation is found
+     */
+    transient static private BLAS nativeBlas = BLAS.getInstance();
+
+    /**
+     * Performs y += a * x
+     *
+     * @param a Scalar a.
+     * @param x Vector x.
+     * @param y Vector y.
+     */
+    public static void axpy(Double a, Vector x, Vector y) {
+        if (x.size() != y.size())
+            throw new CardinalityException(x.size(), y.size());
+
+        if (x.isArrayBased() && y.isArrayBased())
+            axpy(a, x.getStorage().data(), y.getStorage().data());
+        else if (x instanceof SparseLocalVector && y.isArrayBased())
+            axpy(a, (SparseLocalVector)x, y.getStorage().data());
+        else
+            throw new MathIllegalArgumentException("Operation 'axpy' doesn't support this combination of parameters [x="
+                + x.getClass().getName() + ", y="+y.getClass().getName()+"].");
+    }
+
+    /** */
+    private static void axpy(Double a, double[] x, double[] y) {
+        f2jBlas.daxpy(x.length, a, x, 1, y, 1);
+    }
+
+    /** */
+    private static void axpy(Double a, SparseLocalVector x, double[] y) {
+        int xSize = x.size();
+
+        if (a == 1.0) {
+            int k = 0;
+
+            while (k < xSize) {
+                y[k] += x.getX(k);
+                k++;
+            }
+        } else {
+            int k = 0;
+
+            while (k < xSize) {
+                y[k] += a * x.getX(k);
+                k++;
+            }
+        }
+    }
+
+    /**
+     * Returns dot product of vectors x and y.
+     *
+     * @param x Vector x.
+     * @param y Vector y.
+     * @return Dot product of x and y.
+     **/
+    public static Double dot(Vector x, Vector y) {
+        return x.dot(y);
+    }
+
+    /**
+     * Copies Vector x into Vector y. (y = x)
+     *
+     * @param x Vector x.
+     * @param y Vector y.
+     */
+    public void copy(Vector x, Vector y) {
+        int n = y.size();
+
+        if (x.size() != n)
+            throw new CardinalityException(x.size(), n);
+
+        if (y.isArrayBased()) {
+            double[] yData = y.getStorage().data();
+
+            if (x.isArrayBased())
+                System.arraycopy(x.getStorage().data(), 0, y.getStorage().data(), 0, n);
+            else {
+                if (y instanceof SparseLocalVector) {
+                    for (int i = 0; i < n; i++)
+                        yData[i] = x.getX(i);
+                }
+            }
+        } else
+            throw new IllegalArgumentException("Vector y must be array based in copy.");
+    }
+
+
+    /**
+     * Performs in-place multiplication of vector x by a real scalar a. (x = a * x)
+     *
+     * @param a Scalar a.
+     * @param x Vector x.
+     **/
+    public static void scal(Double a, Vector x) {
+        if (x.isArrayBased())
+            f2jBlas.dscal(x.size(), a, x.getStorage().data(), 1);
+        else if (x instanceof SparseLocalVector) {
+            Set<Integer> indexes = ((SparseLocalVector)x).indexes();
+
+            for (Integer i : indexes)
+                x.compute(i, (ind, v) -> v * a);
+        } else
+            throw new IllegalArgumentException();
+    }
+
+    /**
+     * Adds alpha * v * v.t to a matrix in-place. This is the same as BLAS's ?SPR.
+     *
+     * @param u the upper triangular part of the matrix in a [[DenseVector]](column major)
+     */
+    public static void spr(Double alpha, DenseLocalOnHeapVector v, DenseLocalOnHeapVector u) {
+        nativeBlas.dspr("U", v.size(), alpha, v.getStorage().data(), 1, u.getStorage().data());
+    }
+
+    /** */
+    public static void spr(Double alpha, SparseLocalVector v, DenseLocalOnHeapVector u) {
+        int prevNonDfltInd = 0;
+        int startInd = 0;
+        double av;
+        double[] uData = u.getStorage().data();
+
+        for (Integer nonDefaultInd : v.indexes()) {
+            startInd += (nonDefaultInd - prevNonDfltInd) * (nonDefaultInd + prevNonDfltInd + 1) / 2;
+            av = alpha * v.get(nonDefaultInd);
+
+            for (Integer i : v.indexes())
+                if (i <= nonDefaultInd)
+                    uData[startInd + i] += av * v.getX(i);
+
+            prevNonDfltInd = nonDefaultInd;
+        }
+    }
+
+    /**
+     * A := alpha * x * x^T + A
+     * @param alpha a real scalar that will be multiplied to x * x^T^.
+     * @param x the vector x that contains the n elements.
+     * @param a the symmetric matrix A. Size of n x n.
+     */
+    void syr(Double alpha, Vector x, DenseLocalOnHeapMatrix a) {
+        int mA = a.rowSize();
+        int nA = a.columnSize();
+
+        if (mA != nA)
+            throw new NonSquareMatrixException(mA, nA);
+
+        if (mA != x.size())
+            throw new CardinalityException(x.size(), mA);
+
+        // TODO: IGNITE-5535, Process DenseLocalOffHeapVector
+        if (x instanceof DenseLocalOnHeapVector)
+            syr(alpha, x, a);
+        else if (x instanceof SparseLocalVector)
+            syr(alpha, x, a);
+        else
+            throw new IllegalArgumentException("Operation 'syr' does not support vector [class="
+                + x.getClass().getName() + "].");
+    }
+
+    /** */
+    static void syr(Double alpha, DenseLocalOnHeapVector x, DenseLocalOnHeapMatrix a) {
+        int nA = a.rowSize();
+        int mA = a.columnSize();
+
+        nativeBlas.dsyr("U", x.size(), alpha, x.getStorage().data(), 1, a.getStorage().data(), nA);
+
+        // Fill lower triangular part of A
+        int i = 0;
+        while (i < mA) {
+            int j = i + 1;
+
+            while (j < nA) {
+                a.setX(i, j, a.getX(j, i));
+                j++;
+            }
+            i++;
+        }
+    }
+
+    /** */
+    public static void syr(Double alpha, SparseLocalVector x, DenseLocalOnHeapMatrix a) {
+        int mA = a.columnSize();
+
+        for (Integer i : x.indexes()) {
+            double mult = alpha * x.getX(i);
+            for (Integer j : x.indexes())
+                a.getStorage().data()[mA * i + j] += mult * x.getX(j);
+        }
+    }
+
+    /**
+     * For the moment we have no flags indicating if matrix is transposed or not. Therefore all dgemm parameters for
+     * transposition are equal to 'N'.
+     */
+    public static void gemm(Double alpha, Matrix a, DenseLocalOnHeapMatrix b, Double beta, DenseLocalOnHeapMatrix c) {
+        if (alpha == 0.0 && beta == 1.0)
+            return;
+        else if (alpha == 0.0)
+            scal(c, beta);
+        else {
+            if (a instanceof SparseLocalOnHeapMatrix)
+                gemm(alpha, (SparseLocalOnHeapMatrix)a, b, beta, c);
+            else if (a instanceof DenseLocalOnHeapMatrix) {
+                double[] fA = a.getStorage().data();
+                double[] fB = b.getStorage().data();
+                double[] fC = c.getStorage().data();
+
+                nativeBlas.dgemm("N", "N", a.rowSize(), b.columnSize(), a.columnSize(), alpha, fA,
+                    a.rowSize(), fB, b.rowSize(), beta, fC, c.rowSize());
+            } else
+                throw new IllegalArgumentException("Operation 'gemm' doesn't support for matrix [class="
+                    + a.getClass().getName() + "].");
+        }
+    }
+
+    /**
+     * C := alpha * A * B + beta * C
+     * For `SparseMatrix` A.
+     */
+    private static void gemm(Double alpha, SparseLocalOnHeapMatrix a, DenseLocalOnHeapMatrix b, Double beta,
+        DenseLocalOnHeapMatrix c) {
+        int mA = a.rowSize();
+        int nB = b.columnSize();
+        int kA = a.columnSize();
+        int kB = b.rowSize();
+
+        if (kA != kB)
+            throw new CardinalityException(kA, kB);
+
+        if (mA != c.rowSize())
+            throw new CardinalityException(mA, c.rowSize());
+
+        if (nB != c.columnSize())
+            throw new CardinalityException(nB, c.columnSize());
+
+        if (beta != 1.0)
+            scal(c, beta);
+
+        Int2ObjectArrayMap<IntSet> im = a.indexesMap();
+        IntIterator rowsIter = im.keySet().iterator();
+        int row;
+        // We use here this form of iteration instead of 'for' because of nextInt.
+        while (rowsIter.hasNext()) {
+            row = rowsIter.nextInt();
+
+            for (int colInd = 0; colInd < nB; colInd++) {
+                double sum = 0.0;
+
+                IntIterator kIter = im.get(row).iterator();
+                int k;
+
+                while (kIter.hasNext()) {
+                    k = kIter.nextInt();
+                    sum += a.get(row, k) * b.get(k, colInd) * alpha;
+                }
+
+                c.setX(row, colInd, c.getX(row, colInd) + sum);
+            }
+        }
+    }
+
+    /**
+     * y := alpha * A * x + beta * y.
+     *
+     * @param alpha Alpha.
+     * @param a Matrix a.
+     * @param x Vector x.
+     * @param beta Beta.
+     * @param y Vector y.
+     */
+    public static void gemv(double alpha, Matrix a, Vector x, double beta, DenseLocalOnHeapVector y) {
+        checkCardinality(a, x);
+        checkCardinality(a, y);
+
+        if (alpha == 0.0 && beta == 1.0)
+            return;
+
+        if (alpha == 0.0) {
+            scal(y, beta);
+            return;
+        }
+
+        if (a instanceof SparseLocalOnHeapMatrix && x instanceof DenseLocalOnHeapVector)
+            gemv(alpha, (SparseLocalOnHeapMatrix)a, (DenseLocalOnHeapVector)x, beta, y);
+        else if (a instanceof SparseLocalOnHeapMatrix && x instanceof SparseLocalVector)
+            gemv(alpha, (SparseLocalOnHeapMatrix)a, (SparseLocalVector)x, beta, y);
+        else if (a instanceof DenseLocalOnHeapMatrix && x instanceof DenseLocalOnHeapVector)
+            gemv(alpha, (DenseLocalOnHeapMatrix)a, (DenseLocalOnHeapVector)x, beta, y);
+        else if (a instanceof DenseLocalOnHeapMatrix && x instanceof SparseLocalVector)
+            gemv(alpha, (DenseLocalOnHeapMatrix)a, (SparseLocalVector)x, beta, y);
+        else
+            throw new IllegalArgumentException("Operation gemv doesn't support running thist input [matrix=" +
+                a.getClass().getSimpleName() + ", vector=" + x.getClass().getSimpleName()+"].");
+    }
+
+    /**
+     * y := alpha * A * x + beta * y.
+     *
+     * @param alpha Alpha.
+     * @param a Matrix a.
+     * @param x Vector x.
+     * @param beta Beta.
+     * @param y Vector y.
+     */
+    private static void gemv(double alpha, SparseLocalOnHeapMatrix a, DenseLocalOnHeapVector x, double beta,
+        DenseLocalOnHeapVector y) {
+
+        if (beta != 1.0)
+            scal(y, beta);
+
+        IntIterator rowIter = a.indexesMap().keySet().iterator();
+        while (rowIter.hasNext()) {
+            int row = rowIter.nextInt();
+
+            double sum = 0.0;
+            IntIterator colIter = a.indexesMap().get(row).iterator();
+            while (colIter.hasNext()) {
+                int col = colIter.nextInt();
+                sum += alpha * a.getX(row, col) * x.getX(col);
+            }
+
+            y.setX(row, y.getX(row) + sum);
+        }
+    }
+
+    /**
+     * y := alpha * A * x + beta * y.
+     *
+     * @param alpha Alpha.
+     * @param a Matrix a.
+     * @param x Vector x.
+     * @param beta Beta.
+     * @param y Vector y.
+     */
+    private static void gemv(double alpha, DenseLocalOnHeapMatrix a, DenseLocalOnHeapVector x, double beta,
+        DenseLocalOnHeapVector y) {
+        nativeBlas.dgemv("N", a.rowSize(), a.columnSize(), alpha, a.getStorage().data(), a.rowSize(), x.getStorage().data(), 1, beta,
+            y.getStorage().data(), 1);
+    }
+
+    /**
+     * y := alpha * A * x + beta * y.
+     *
+     * @param alpha Alpha.
+     * @param a Matrix a.
+     * @param x Vector x.
+     * @param beta Beta.
+     * @param y Vector y.
+     */
+    private static void gemv(double alpha, SparseLocalOnHeapMatrix a, SparseLocalVector x, double beta,
+        DenseLocalOnHeapVector y) {
+
+
+        if (beta != 1.0)
+            scal(y, beta);
+
+        IntIterator rowIter = a.indexesMap().keySet().iterator();
+        while (rowIter.hasNext()) {
+            int row = rowIter.nextInt();
+
+            double sum = 0.0;
+            IntIterator colIter = a.indexesMap().get(row).iterator();
+            while (colIter.hasNext()) {
+                int col = colIter.nextInt();
+
+                sum += alpha * a.getX(row, col) * x.getX(col);
+            }
+
+            y.set(row, y.get(row) + sum);
+        }
+    }
+
+    /**
+     * y := alpha * A * x + beta * y.
+     *
+     * @param alpha Alpha.
+     * @param a Matrix a.
+     * @param x Vector x.
+     * @param beta Beta.
+     * @param y Vector y.
+     */
+    private static void gemv(double alpha, DenseLocalOnHeapMatrix a, SparseLocalVector x, double beta,
+        DenseLocalOnHeapVector y) {
+        int rowCntrForA = 0;
+        int mA = a.rowSize();
+
+        double[] aData = a.getStorage().data();
+
+        IntSet indexes = x.indexes();
+
+        double[] yValues = y.getStorage().data();
+
+        while (rowCntrForA < mA) {
+            double sum = 0.0;
+
+            IntIterator iter = indexes.iterator();
+            while (iter.hasNext()) {
+                int xIdx = iter.nextInt();
+                sum += x.getX(xIdx) * aData[xIdx * mA + rowCntrForA];
+            }
+
+            yValues[rowCntrForA] = sum * alpha + beta * yValues[rowCntrForA];
+            rowCntrForA++;
+        }
+    }
+
+    /**
+     * M := alpha * M.
+     * @param m Matrix M.
+     * @param alpha Aplha.
+     */
+    private static void scal(Matrix m, double alpha) {
+        if (alpha != 1.0)
+            for (int i = 0; i < m.rowSize(); i++)
+                for (int j = 0; j < m.columnSize(); j++)
+                    m.setX(i, j, m.getX(i, j) * alpha);
+
+    }
+
+    /**
+     * v := alpha * v.
+     * @param v Vector v.
+     * @param alpha Aplha.
+     */
+    private static void scal(Vector v, double alpha) {
+        if (alpha != 1.0)
+            for (int i = 0; i < v.size(); i++)
+                v.compute(i, (ind, val) -> val * alpha);
+    }
+
+    /**
+     * Checks if Matrix A can be multiplied by vector v, if not CardinalityException is thrown.
+     *
+     * @param a Matrix A.
+     * @param v Vector v.
+     */
+    public static void checkCardinality(Matrix a, Vector v) throws CardinalityException {
+        if (a.columnSize() != v.size())
+            throw new CardinalityException(a.columnSize(), v.size());
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/Matrix.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/Matrix.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/Matrix.java
index 2cf4e63..66de1a1 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/Matrix.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/Matrix.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.ml.math;
 
 import java.io.Externalizable;
+import java.util.Spliterator;
 import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.ml.math.exceptions.CardinalityException;
 import org.apache.ignite.ml.math.exceptions.IndexException;
@@ -25,6 +26,7 @@ import org.apache.ignite.ml.math.exceptions.UnsupportedOperationException;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteDoubleFunction;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
+import org.apache.ignite.ml.math.functions.IgniteTriFunction;
 import org.apache.ignite.ml.math.functions.IntIntToDoubleFunction;
 
 /**
@@ -187,6 +189,27 @@ public interface Matrix extends MetaAttributes, Externalizable, StorageOpsMetric
     public Matrix map(Matrix mtx, IgniteBiFunction<Double, Double, Double> fun);
 
     /**
+     * Gets number of non-zero elements in this matrix.
+     *
+     * @return Number of non-zero elements in this matrix.
+     */
+    public int nonZeroElements();
+
+    /**
+     * Gets spliterator for all values in this matrix.
+     *
+     * @return Spliterator for all values.
+     */
+    public Spliterator<Double> allSpliterator();
+
+    /**
+     * Gets spliterator for all non-zero values in this matrix.
+     *
+     * @return Spliterator for all non-zero values.
+     */
+    public Spliterator<Double> nonZeroSpliterator();
+
+    /**
      * Assigns values from given vector to the specified column in this matrix.
      *
      * @param col Column index.
@@ -515,4 +538,12 @@ public interface Matrix extends MetaAttributes, Externalizable, StorageOpsMetric
     public default void destroy() {
         // No-op.
     }
+
+    /**
+     * Replace matrix entry with value oldVal at (row, col) with result of computing f(row, col, oldVal).
+     * @param row Row.
+     * @param col Column.
+     * @param f Function used for replacing.
+     */
+    public void compute(int row, int col, IgniteTriFunction<Integer, Integer, Double, Double> f);
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/MatrixStorage.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/MatrixStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/MatrixStorage.java
index ccfebe5..3b905bc 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/MatrixStorage.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/MatrixStorage.java
@@ -52,7 +52,7 @@ public interface MatrixStorage extends Externalizable, StorageOpsMetrics, Destro
      *
      * @see StorageOpsMetrics#isArrayBased()
      */
-    default public double[][] data() {
+    default public double[] data() {
         return null;
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/OrderedMatrix.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/OrderedMatrix.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/OrderedMatrix.java
new file mode 100644
index 0000000..2c3acc8
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/OrderedMatrix.java
@@ -0,0 +1,24 @@
+/*
+ * 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.math;
+
+/** Interface for matrix with particular order for storing entities. */
+public interface OrderedMatrix {
+    /** Get access mode. */
+    public int accessMode();
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/Vector.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/Vector.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/Vector.java
index e1c5df0..5fd39af 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/Vector.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/Vector.java
@@ -26,6 +26,7 @@ import org.apache.ignite.ml.math.exceptions.IndexException;
 import org.apache.ignite.ml.math.exceptions.UnsupportedOperationException;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteDoubleFunction;
+import org.apache.ignite.ml.math.functions.IgniteIntDoubleToDoubleBiFunction;
 
 /**
  * A vector interface.
@@ -496,4 +497,11 @@ public interface Vector extends MetaAttributes, Externalizable, StorageOpsMetric
      * @return Vector GUID.
      */
     public IgniteUuid guid();
+
+    /**
+     * Replace vector entry with value oldVal at i with result of computing f(i, oldVal).
+     * @param i Position.
+     * @param f Function used for replacing.
+     **/
+    public void compute(int i, IgniteIntDoubleToDoubleBiFunction f);
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/decompositions/CholeskyDecomposition.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/decompositions/CholeskyDecomposition.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/decompositions/CholeskyDecomposition.java
index 84028fe..73fbe2c 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/decompositions/CholeskyDecomposition.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/decompositions/CholeskyDecomposition.java
@@ -23,6 +23,7 @@ import org.apache.ignite.ml.math.Vector;
 import org.apache.ignite.ml.math.exceptions.CardinalityException;
 import org.apache.ignite.ml.math.exceptions.NonPositiveDefiniteMatrixException;
 import org.apache.ignite.ml.math.exceptions.NonSymmetricMatrixException;
+import org.apache.ignite.ml.math.util.MatrixUtil;
 
 import static org.apache.ignite.ml.math.util.MatrixUtil.like;
 import static org.apache.ignite.ml.math.util.MatrixUtil.likeVector;
@@ -252,7 +253,7 @@ public class CholeskyDecomposition implements Destroyable {
             throw new CardinalityException(b.rowSize(), m);
 
         final int nColB = b.columnSize();
-        final double[][] x = b.getStorage().data();
+        final double[][] x = MatrixUtil.unflatten(b.getStorage().data(), b.columnSize());
 
         // Solve LY = b
         for (int j = 0; j < m; j++) {
@@ -295,15 +296,13 @@ public class CholeskyDecomposition implements Destroyable {
     /** */
     private double[][] toDoubleArr(Matrix mtx) {
         if (mtx.isArrayBased())
-            return mtx.getStorage().data();
+            return MatrixUtil.unflatten(mtx.getStorage().data(), mtx.columnSize());
 
-        double[][] res = new double[mtx.rowSize()][];
+        double[][] res = new double[mtx.rowSize()][mtx.columnSize()];
 
-        for (int row = 0; row < mtx.rowSize(); row++) {
-            res[row] = new double[mtx.columnSize()];
+        for (int row = 0; row < mtx.rowSize(); row++)
             for (int col = 0; col < mtx.columnSize(); col++)
                 res[row][col] = mtx.get(row, col);
-        }
 
         return res;
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteIntDoubleToDoubleBiFunction.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteIntDoubleToDoubleBiFunction.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteIntDoubleToDoubleBiFunction.java
new file mode 100644
index 0000000..c9a91ae
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteIntDoubleToDoubleBiFunction.java
@@ -0,0 +1,27 @@
+/*
+ * 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.math.functions;
+
+import java.io.Serializable;
+
+/** BiFunction (int, double) -> double. */
+@FunctionalInterface
+public interface IgniteIntDoubleToDoubleBiFunction extends Serializable {
+    /** */
+    public double apply(int x, double d);
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteIntIntToIntBiFunction.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteIntIntToIntBiFunction.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteIntIntToIntBiFunction.java
new file mode 100644
index 0000000..bfd472c
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteIntIntToIntBiFunction.java
@@ -0,0 +1,27 @@
+/*
+ * 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.math.functions;
+
+import java.io.Serializable;
+
+/** BiFunction (int, int) -> int. */
+@FunctionalInterface
+public interface IgniteIntIntToIntBiFunction extends Serializable {
+    /** */
+    public int apply(int x, int y);
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteTriFunction.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteTriFunction.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteTriFunction.java
new file mode 100644
index 0000000..3284a00
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/functions/IgniteTriFunction.java
@@ -0,0 +1,35 @@
+/*
+ * 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.math.functions;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.function.Function;
+
+/** Serializable TriFunction (A, B, C) -> R. */
+@FunctionalInterface
+public interface IgniteTriFunction<A,B,C,R> extends Serializable {
+    /** */
+    R apply(A a, B b, C c);
+
+    /** */
+    default <V> IgniteTriFunction<A, B, C, V> andThen(Function<? super R, ? extends V> after) {
+        Objects.requireNonNull(after);
+        return (A a, B b, C c) -> after.apply(apply(a, b, c));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/AbstractMatrix.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/AbstractMatrix.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/AbstractMatrix.java
index 647ebc6..e1efd0c 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/AbstractMatrix.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/AbstractMatrix.java
@@ -24,6 +24,8 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Random;
+import java.util.Spliterator;
+import java.util.function.Consumer;
 import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.ml.math.Matrix;
 import org.apache.ignite.ml.math.MatrixStorage;
@@ -36,6 +38,7 @@ import org.apache.ignite.ml.math.functions.Functions;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteDoubleFunction;
 import org.apache.ignite.ml.math.functions.IgniteFunction;
+import org.apache.ignite.ml.math.functions.IgniteTriFunction;
 import org.apache.ignite.ml.math.functions.IntIntToDoubleFunction;
 import org.apache.ignite.ml.math.impls.vector.MatrixVectorView;
 
@@ -326,8 +329,7 @@ public abstract class AbstractMatrix implements Matrix {
     /** {@inheritDoc} */
     @Override public Matrix assign(double val) {
         if (sto.isArrayBased())
-            for (double[] column : sto.data())
-                Arrays.fill(column, val);
+                Arrays.fill(sto.data(), val);
         else {
             int rows = rowSize();
             int cols = columnSize();
@@ -421,6 +423,85 @@ public abstract class AbstractMatrix implements Matrix {
     }
 
     /** {@inheritDoc} */
+    @Override public Spliterator<Double> allSpliterator() {
+        return new Spliterator<Double>() {
+            /** {@inheritDoc} */
+            @Override public boolean tryAdvance(Consumer<? super Double> act) {
+                int rLen = rowSize();
+                int cLen = columnSize();
+
+                for (int i = 0; i < rLen; i++)
+                    for (int j = 0; j < cLen; j++)
+                        act.accept(storageGet(i, j));
+
+                return true;
+            }
+
+            /** {@inheritDoc} */
+            @Override public Spliterator<Double> trySplit() {
+                return null; // No Splitting.
+            }
+
+            /** {@inheritDoc} */
+            @Override public long estimateSize() {
+                return rowSize() * columnSize();
+            }
+
+            /** {@inheritDoc} */
+            @Override public int characteristics() {
+                return ORDERED | SIZED;
+            }
+        };
+    }
+
+    /** {@inheritDoc} */
+    @Override public int nonZeroElements() {
+        int cnt = 0;
+
+        for (int i = 0; i < rowSize(); i++)
+            for (int j = 0; j < rowSize(); j++)
+                if (get(i, j) != 0.0)
+                    cnt++;
+
+        return cnt;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Spliterator<Double> nonZeroSpliterator() {
+        return new Spliterator<Double>() {
+            /** {@inheritDoc} */
+            @Override public boolean tryAdvance(Consumer<? super Double> act) {
+                int rLen = rowSize();
+                int cLen = columnSize();
+
+                for (int i = 0; i < rLen; i++)
+                    for (int j = 0; j < cLen; j++) {
+                        double val = storageGet(i, j);
+
+                        if (val != 0.0)
+                            act.accept(val);
+                    }
+                return true;
+            }
+
+            /** {@inheritDoc} */
+            @Override public Spliterator<Double> trySplit() {
+                return null; // No Splitting.
+            }
+
+            /** {@inheritDoc} */
+            @Override public long estimateSize() {
+                return nonZeroElements();
+            }
+
+            /** {@inheritDoc} */
+            @Override public int characteristics() {
+                return ORDERED | SIZED;
+            }
+        };
+    }
+
+    /** {@inheritDoc} */
     @Override public Matrix assignColumn(int col, Vector vec) {
         checkColumnIndex(col);
 
@@ -442,7 +523,7 @@ public abstract class AbstractMatrix implements Matrix {
             throw new CardinalityException(cols, vec.size());
 
         if (sto.isArrayBased() && vec.getStorage().isArrayBased())
-            System.arraycopy(vec.getStorage().data(), 0, sto.data()[row], 0, cols);
+            System.arraycopy(vec.getStorage().data(), 0, sto.data(), cols * row, cols);
         else
             for (int y = 0; y < cols; y++)
                 storageSet(row, y, vec.getX(y));
@@ -623,7 +704,7 @@ public abstract class AbstractMatrix implements Matrix {
             throw new CardinalityException(cols, data.length);
 
         if (sto.isArrayBased())
-            System.arraycopy(data, 0, sto.data()[row], 0, cols);
+            System.arraycopy(data, 0, sto.data(), row * cols, cols);
         else
             for (int y = 0; y < cols; y++)
                 setX(row, y, data[y]);
@@ -880,4 +961,9 @@ public abstract class AbstractMatrix implements Matrix {
 
         return (sto != null ? sto.equals(that.getStorage()) : that.getStorage() == null);
     }
+
+    /** {@inheritDoc} */
+    @Override public void compute(int row, int col, IgniteTriFunction<Integer, Integer, Double, Double> f) {
+        setX(row, col, f.apply(row, col, getX(row, col)));
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/DenseLocalOnHeapMatrix.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/DenseLocalOnHeapMatrix.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/DenseLocalOnHeapMatrix.java
index f95e0cc..393fff6 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/DenseLocalOnHeapMatrix.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/DenseLocalOnHeapMatrix.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.ml.math.impls.matrix;
 
 import org.apache.ignite.ml.math.Matrix;
+import org.apache.ignite.ml.math.OrderedMatrix;
+import org.apache.ignite.ml.math.StorageConstants;
 import org.apache.ignite.ml.math.Vector;
 import org.apache.ignite.ml.math.impls.storage.matrix.ArrayMatrixStorage;
 import org.apache.ignite.ml.math.impls.vector.DenseLocalOnHeapVector;
@@ -30,7 +32,7 @@ import org.apache.ignite.ml.math.impls.vector.DenseLocalOnHeapVector;
  * local, non-distributed execution is satisfactory and on-heap JVM storage is enough
  * to keep the entire data set.
  */
-public class DenseLocalOnHeapMatrix extends AbstractMatrix {
+public class DenseLocalOnHeapMatrix extends AbstractMatrix implements OrderedMatrix {
     /**
      *
      */
@@ -43,44 +45,89 @@ public class DenseLocalOnHeapMatrix extends AbstractMatrix {
      * @param cols Amount of columns in matrix.
      */
     public DenseLocalOnHeapMatrix(int rows, int cols) {
+        this(rows, cols, StorageConstants.ROW_STORAGE_MODE);
+    }
+
+    /**
+     * @param rows Amount of rows in matrix.
+     * @param cols Amount of columns in matrix.
+     * @param acsMode Storage order (row or column-based).
+     */
+    public DenseLocalOnHeapMatrix(int rows, int cols, int acsMode) {
         assert rows > 0;
         assert cols > 0;
 
-        setStorage(new ArrayMatrixStorage(rows, cols));
+        setStorage(new ArrayMatrixStorage(rows, cols, acsMode));
+    }
+
+    /**
+     * @param mtx Backing data array.
+     * @param acsMode Access mode.
+     */
+    public DenseLocalOnHeapMatrix(double[][] mtx, int acsMode) {
+        assert mtx != null;
+
+        setStorage(new ArrayMatrixStorage(mtx, acsMode));
     }
 
     /**
      * @param mtx Backing data array.
      */
     public DenseLocalOnHeapMatrix(double[][] mtx) {
+        this(mtx, StorageConstants.ROW_STORAGE_MODE);
+    }
+
+    /**
+     * @param mtx Backing data array.
+     * @param acsMode Access mode.
+     */
+    public DenseLocalOnHeapMatrix(double[] mtx, int rows, int acsMode) {
         assert mtx != null;
 
-        setStorage(new ArrayMatrixStorage(mtx));
+        setStorage(new ArrayMatrixStorage(mtx, rows, acsMode));
     }
 
     /**
-     * @param orig Original matrix.
+     * Build new matrix from flat raw array.
      */
+    public DenseLocalOnHeapMatrix(double[] mtx, int rows) {
+        this(mtx, StorageConstants.ROW_STORAGE_MODE, rows);
+    }
+
+    /** */
     private DenseLocalOnHeapMatrix(DenseLocalOnHeapMatrix orig) {
+        this(orig, orig.accessMode());
+    }
+
+    /**
+     * @param orig Original matrix.
+     * @param acsMode Access mode.
+     */
+    private DenseLocalOnHeapMatrix(DenseLocalOnHeapMatrix orig, int acsMode) {
         assert orig != null;
 
-        setStorage(new ArrayMatrixStorage(orig.rowSize(), orig.columnSize()));
+        setStorage(new ArrayMatrixStorage(orig.rowSize(), orig.columnSize(), acsMode));
 
         assign(orig);
     }
 
     /** {@inheritDoc} */
     @Override public Matrix copy() {
-        return new DenseLocalOnHeapMatrix(this);
+        return new DenseLocalOnHeapMatrix(this, accessMode());
     }
 
     /** {@inheritDoc} */
     @Override public Matrix like(int rows, int cols) {
-        return new DenseLocalOnHeapMatrix(rows, cols);
+        return new DenseLocalOnHeapMatrix(rows, cols, getStorage() != null ? accessMode() : StorageConstants.ROW_STORAGE_MODE);
     }
 
     /** {@inheritDoc} */
     @Override public Vector likeVector(int crd) {
         return new DenseLocalOnHeapVector(crd);
     }
+
+    /** */
+    @Override public int accessMode() {
+        return ((ArrayMatrixStorage)getStorage()).accessMode();
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/SparseLocalOnHeapMatrix.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/SparseLocalOnHeapMatrix.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/SparseLocalOnHeapMatrix.java
index d711295..d0a5937 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/SparseLocalOnHeapMatrix.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/matrix/SparseLocalOnHeapMatrix.java
@@ -17,10 +17,14 @@
 
 package org.apache.ignite.ml.math.impls.matrix;
 
+import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
+import it.unimi.dsi.fastutil.ints.IntIterator;
+import it.unimi.dsi.fastutil.ints.IntSet;
 import org.apache.ignite.ml.math.Matrix;
 import org.apache.ignite.ml.math.MatrixStorage;
 import org.apache.ignite.ml.math.StorageConstants;
 import org.apache.ignite.ml.math.Vector;
+import org.apache.ignite.ml.math.functions.IgniteTriFunction;
 import org.apache.ignite.ml.math.impls.storage.matrix.SparseLocalOnHeapMatrixStorage;
 import org.apache.ignite.ml.math.impls.vector.SparseLocalVector;
 
@@ -62,6 +66,24 @@ public class SparseLocalOnHeapMatrix extends AbstractMatrix implements StorageCo
     }
 
     /** {@inheritDoc} */
+    @Override public int nonZeroElements() {
+        int res = 0;
+        IntIterator rowIter = indexesMap().keySet().iterator();
+
+        while (rowIter.hasNext()) {
+            int row = rowIter.nextInt();
+            res += indexesMap().get(row).size();
+        }
+
+        return res;
+    }
+
+    /** */
+    public Int2ObjectArrayMap<IntSet> indexesMap() {
+        return ((SparseLocalOnHeapMatrixStorage)getStorage()).indexesMap();
+    }
+
+    /** {@inheritDoc} */
     @Override public Matrix copy() {
         Matrix cp = like(rowSize(), columnSize());
 
@@ -69,4 +91,9 @@ public class SparseLocalOnHeapMatrix extends AbstractMatrix implements StorageCo
 
         return cp;
     }
+
+    /** {@inheritDoc} */
+    @Override public void compute(int row, int col, IgniteTriFunction<Integer, Integer, Double, Double> f) {
+        ((SparseLocalOnHeapMatrixStorage)getStorage()).compute(row, col, f);
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/ArrayMatrixStorage.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/ArrayMatrixStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/ArrayMatrixStorage.java
index 397bf93..1f337fd 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/ArrayMatrixStorage.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/ArrayMatrixStorage.java
@@ -22,17 +22,24 @@ import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.util.Arrays;
 import org.apache.ignite.ml.math.MatrixStorage;
+import org.apache.ignite.ml.math.StorageConstants;
+import org.apache.ignite.ml.math.functions.IgniteIntIntToIntBiFunction;
+import org.apache.ignite.ml.math.util.MatrixUtil;
 
 /**
  * Array based {@link MatrixStorage} implementation.
  */
 public class ArrayMatrixStorage implements MatrixStorage {
     /** Backing data array. */
-    private double[][] data;
+    private double[] data;
     /** Amount of rows in the matrix. */
     private int rows;
     /** Amount of columns in the matrix. */
     private int cols;
+    /** Mode specifying if this matrix is row-major or column-major. */
+    private int acsMode;
+    /** Index mapper */
+    private IgniteIntIntToIntBiFunction idxMapper;
 
     /**
      *
@@ -46,32 +53,62 @@ public class ArrayMatrixStorage implements MatrixStorage {
      * @param cols Amount of columns in the matrix.
      */
     public ArrayMatrixStorage(int rows, int cols) {
+        this(rows, cols, StorageConstants.ROW_STORAGE_MODE);
+    }
+
+    /** */
+    public ArrayMatrixStorage(int rows, int cols, int acsMode) {
         assert rows > 0;
         assert cols > 0;
 
-        this.data = new double[rows][cols];
+        this.data = new double[rows * cols];
         this.rows = rows;
         this.cols = cols;
+        idxMapper = indexMapper(acsMode);
+        this.acsMode = acsMode;
+    }
+
+    /**
+     * @param data Backing data array.
+     */
+    public ArrayMatrixStorage(double[][] data, int acsMode) {
+        this(MatrixUtil.flatten(data, acsMode), data.length, acsMode);
     }
 
     /**
      * @param data Backing data array.
      */
     public ArrayMatrixStorage(double[][] data) {
+        this(MatrixUtil.flatten(data, StorageConstants.ROW_STORAGE_MODE), data.length);
+    }
+
+    /**
+     * @param data Backing data array.
+     */
+    public ArrayMatrixStorage(double[] data, int rows, int acsMode) {
         assert data != null;
-        assert data[0] != null;
+        assert data.length % rows == 0;
 
         this.data = data;
-        this.rows = data.length;
-        this.cols = data[0].length;
+        this.rows = rows;
+        this.cols = data.length / rows;
+        idxMapper = indexMapper(acsMode);
+        this.acsMode = acsMode;
 
         assert rows > 0;
         assert cols > 0;
     }
 
+    /**
+     * @param data Backing data array.
+     */
+    public ArrayMatrixStorage(double[] data, int rows) {
+        this(data, rows, StorageConstants.ROW_STORAGE_MODE);
+    }
+
     /** {@inheritDoc} */
     @Override public double get(int x, int y) {
-        return data[x][y];
+        return data[idxMapper.apply(x, y)];
     }
 
     /** {@inheritDoc} */
@@ -96,7 +133,7 @@ public class ArrayMatrixStorage implements MatrixStorage {
 
     /** {@inheritDoc} */
     @Override public void set(int x, int y, double v) {
-        data[x][y] = v;
+        data[idxMapper.apply(x, y)] = v;
     }
 
     /** {@inheritDoc} */
@@ -115,14 +152,25 @@ public class ArrayMatrixStorage implements MatrixStorage {
     }
 
     /** {@inheritDoc} */
-    @Override public double[][] data() {
+    @Override public double[] data() {
         return data;
     }
 
+    /**
+     * Get the index mapper for given access mode.
+     *
+     * @param acsMode Access mode.
+     */
+    private IgniteIntIntToIntBiFunction indexMapper(int acsMode) {
+        return acsMode == StorageConstants.ROW_STORAGE_MODE ? (r, c) -> r * cols + c :
+            (r, c) -> c * rows + r;
+    }
+
     /** {@inheritDoc} */
     @Override public void writeExternal(ObjectOutput out) throws IOException {
         out.writeInt(rows);
         out.writeInt(cols);
+        out.writeInt(acsMode);
 
         out.writeObject(data);
     }
@@ -131,8 +179,15 @@ public class ArrayMatrixStorage implements MatrixStorage {
     @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
         rows = in.readInt();
         cols = in.readInt();
+        acsMode = in.readInt();
+        idxMapper = indexMapper(acsMode);
+
+        data = (double[])in.readObject();
+    }
 
-        data = (double[][])in.readObject();
+    /** Get the access mode of this storage. */
+    public int accessMode() {
+        return acsMode;
     }
 
     /** {@inheritDoc} */
@@ -141,7 +196,8 @@ public class ArrayMatrixStorage implements MatrixStorage {
 
         res += res * 37 + rows;
         res += res * 37 + cols;
-        res += res * 37 + Arrays.deepHashCode(data);
+        res += res * 37 + acsMode;
+        res += res * 37 + Arrays.hashCode(data);
 
         return res;
     }
@@ -156,6 +212,6 @@ public class ArrayMatrixStorage implements MatrixStorage {
 
         ArrayMatrixStorage that = (ArrayMatrixStorage)o;
 
-        return Arrays.deepEquals(data, that.data);
+        return acsMode == that.acsMode && Arrays.equals(data, that.data);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/DenseOffHeapMatrixStorage.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/DenseOffHeapMatrixStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/DenseOffHeapMatrixStorage.java
index 7405a4e..f58da65 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/DenseOffHeapMatrixStorage.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/DenseOffHeapMatrixStorage.java
@@ -122,7 +122,7 @@ public class DenseOffHeapMatrixStorage implements MatrixStorage {
     }
 
     /** {@inheritDoc} */
-    @Override public double[][] data() {
+    @Override public double[] data() {
         return null;
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixDelegateStorage.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixDelegateStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixDelegateStorage.java
index 1f77d0f..f185479 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixDelegateStorage.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixDelegateStorage.java
@@ -150,7 +150,7 @@ public class MatrixDelegateStorage implements MatrixStorage {
     }
 
     /** {@inheritDoc} */
-    @Override public double[][] data() {
+    @Override public double[] data() {
         return sto.data();
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/SparseDistributedMatrixStorage.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/SparseDistributedMatrixStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/SparseDistributedMatrixStorage.java
index 1513502..fc7d969 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/SparseDistributedMatrixStorage.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/SparseDistributedMatrixStorage.java
@@ -116,9 +116,7 @@ public class SparseDistributedMatrixStorage extends CacheUtils implements Matrix
         // Random cache name.
         cfg.setName(ML_CACHE_NAME);
 
-        IgniteCache<IgniteBiTuple<Integer, IgniteUuid>, Map<Integer, Double>> cache = Ignition.localIgnite().getOrCreateCache(cfg);
-
-        return cache;
+        return Ignition.localIgnite().getOrCreateCache(cfg);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/SparseLocalOnHeapMatrixStorage.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/SparseLocalOnHeapMatrixStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/SparseLocalOnHeapMatrixStorage.java
index b33cb26..daf1d4b 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/SparseLocalOnHeapMatrixStorage.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/matrix/SparseLocalOnHeapMatrixStorage.java
@@ -19,6 +19,8 @@ package org.apache.ignite.ml.math.impls.storage.matrix;
 
 import it.unimi.dsi.fastutil.ints.Int2DoubleOpenHashMap;
 import it.unimi.dsi.fastutil.ints.Int2DoubleRBTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
+import it.unimi.dsi.fastutil.ints.IntSet;
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
@@ -26,6 +28,7 @@ import java.util.HashMap;
 import java.util.Map;
 import org.apache.ignite.ml.math.MatrixStorage;
 import org.apache.ignite.ml.math.StorageConstants;
+import org.apache.ignite.ml.math.functions.IgniteTriFunction;
 
 /**
  * Storage for sparse, local, on-heap matrix.
@@ -225,4 +228,19 @@ public class SparseLocalOnHeapMatrixStorage implements MatrixStorage, StorageCon
         return rows == that.rows && cols == that.cols && acsMode == that.acsMode && stoMode == that.stoMode
             && (sto != null ? sto.equals(that.sto) : that.sto == null);
     }
+
+    /** */
+    public void compute(int row, int col, IgniteTriFunction<Integer, Integer, Double, Double> f) {
+        sto.get(row).compute(col, (c, val) -> f.apply(row, c, val));
+    }
+
+    /** */
+    public Int2ObjectArrayMap<IntSet> indexesMap() {
+        Int2ObjectArrayMap<IntSet> res = new Int2ObjectArrayMap<>();
+
+        for (Integer row : sto.keySet())
+            res.put(row.intValue(), (IntSet)sto.get(row).keySet());
+
+        return res;
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/vector/SparseLocalOnHeapVectorStorage.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/vector/SparseLocalOnHeapVectorStorage.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/vector/SparseLocalOnHeapVectorStorage.java
index deef010..3323a07 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/vector/SparseLocalOnHeapVectorStorage.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/storage/vector/SparseLocalOnHeapVectorStorage.java
@@ -19,6 +19,7 @@ package org.apache.ignite.ml.math.impls.storage.vector;
 
 import it.unimi.dsi.fastutil.ints.Int2DoubleOpenHashMap;
 import it.unimi.dsi.fastutil.ints.Int2DoubleRBTreeMap;
+import it.unimi.dsi.fastutil.ints.IntSet;
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
@@ -178,4 +179,9 @@ public class SparseLocalOnHeapVectorStorage implements VectorStorage, StorageCon
 
         return res;
     }
+
+    /** */
+    public IntSet indexes() {
+        return (IntSet)sto.keySet();
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/AbstractReadOnlyVector.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/AbstractReadOnlyVector.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/AbstractReadOnlyVector.java
index e48542b..1de334f 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/AbstractReadOnlyVector.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/AbstractReadOnlyVector.java
@@ -22,6 +22,7 @@ import org.apache.ignite.ml.math.Vector;
 import org.apache.ignite.ml.math.VectorStorage;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteDoubleFunction;
+import org.apache.ignite.ml.math.functions.IgniteIntDoubleToDoubleBiFunction;
 import org.apache.ignite.ml.math.impls.matrix.FunctionMatrix;
 
 /**
@@ -122,4 +123,9 @@ public abstract class AbstractReadOnlyVector extends AbstractVector {
 
         return new FunctionVector(size(), (idx) -> Math.log1p(get(idx)) / denominator);
     }
+
+    /** {@inheritDoc} */
+    @Override public void compute(int idx, IgniteIntDoubleToDoubleBiFunction f) {
+        throw new UnsupportedOperationException();
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/AbstractVector.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/AbstractVector.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/AbstractVector.java
index 83ac837..131a610 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/AbstractVector.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/AbstractVector.java
@@ -38,6 +38,7 @@ import org.apache.ignite.ml.math.exceptions.UnsupportedOperationException;
 import org.apache.ignite.ml.math.functions.Functions;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteDoubleFunction;
+import org.apache.ignite.ml.math.functions.IgniteIntDoubleToDoubleBiFunction;
 import org.apache.ignite.ml.math.impls.matrix.MatrixView;
 import org.jetbrains.annotations.NotNull;
 
@@ -904,4 +905,11 @@ public abstract class AbstractVector implements Vector {
 
         return (sto != null ? sto.equals(that.sto) : that.sto == null);
     }
+
+    /** {@inheritDoc} */
+    @Override public void compute(int idx, IgniteIntDoubleToDoubleBiFunction f) {
+        storageSet(idx, f.apply(idx, storageGet(idx)));
+        lenSq = 0.0;
+        maxElm = minElm = null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/DelegatingVector.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/DelegatingVector.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/DelegatingVector.java
index 48fbd06..1df9acc 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/DelegatingVector.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/DelegatingVector.java
@@ -30,6 +30,7 @@ import org.apache.ignite.ml.math.Vector;
 import org.apache.ignite.ml.math.VectorStorage;
 import org.apache.ignite.ml.math.functions.IgniteBiFunction;
 import org.apache.ignite.ml.math.functions.IgniteDoubleFunction;
+import org.apache.ignite.ml.math.functions.IgniteIntDoubleToDoubleBiFunction;
 
 /**
  * Convenient class that can be used to add decorations to an existing vector. Subclasses
@@ -367,6 +368,11 @@ public class DelegatingVector implements Vector {
     }
 
     /** {@inheritDoc} */
+    @Override public void compute(int i, IgniteIntDoubleToDoubleBiFunction f) {
+        dlg.compute(i, f);
+    }
+
+    /** {@inheritDoc} */
     @Override public void destroy() {
         dlg.destroy();
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/SparseLocalVector.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/SparseLocalVector.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/SparseLocalVector.java
index 9e345bb..bc1e59d 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/SparseLocalVector.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/impls/vector/SparseLocalVector.java
@@ -17,7 +17,11 @@
 
 package org.apache.ignite.ml.math.impls.vector;
 
+import it.unimi.dsi.fastutil.ints.IntSet;
 import java.util.Map;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
 import org.apache.ignite.ml.math.Matrix;
 import org.apache.ignite.ml.math.StorageConstants;
 import org.apache.ignite.ml.math.Vector;
@@ -77,4 +81,39 @@ public class SparseLocalVector extends AbstractVector implements StorageConstant
         else
             return super.times(x);
     }
+
+    /** Indexes of non-default elements. */
+    public IntSet indexes() {
+        return storage().indexes();
+    }
+
+    /** {@inheritDoc} */
+    @Override public Spliterator<Double> nonZeroSpliterator() {
+        return new Spliterator<Double>() {
+            /** {@inheritDoc} */
+            @Override public boolean tryAdvance(Consumer<? super Double> act) {
+                Set<Integer> indexes = storage().indexes();
+
+                for (Integer index : indexes)
+                    act.accept(storageGet(index));
+
+                return true;
+            }
+
+            /** {@inheritDoc} */
+            @Override public Spliterator<Double> trySplit() {
+                return null; // No Splitting.
+            }
+
+            /** {@inheritDoc} */
+            @Override public long estimateSize() {
+                return storage().indexes().size();
+            }
+
+            /** {@inheritDoc} */
+            @Override public int characteristics() {
+                return ORDERED | SIZED;
+            }
+        };
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/main/java/org/apache/ignite/ml/math/util/MatrixUtil.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/ml/math/util/MatrixUtil.java b/modules/ml/src/main/java/org/apache/ignite/ml/math/util/MatrixUtil.java
index 752929d..c727e44 100644
--- a/modules/ml/src/main/java/org/apache/ignite/ml/math/util/MatrixUtil.java
+++ b/modules/ml/src/main/java/org/apache/ignite/ml/math/util/MatrixUtil.java
@@ -20,12 +20,14 @@ package org.apache.ignite.ml.math.util;
 import java.util.List;
 import org.apache.ignite.internal.util.GridArgumentCheck;
 import org.apache.ignite.ml.math.Matrix;
+import org.apache.ignite.ml.math.StorageConstants;
 import org.apache.ignite.ml.math.Vector;
 import org.apache.ignite.ml.math.impls.matrix.CacheMatrix;
 import org.apache.ignite.ml.math.impls.matrix.DenseLocalOnHeapMatrix;
 import org.apache.ignite.ml.math.impls.matrix.MatrixView;
 import org.apache.ignite.ml.math.impls.matrix.PivotedMatrixView;
 import org.apache.ignite.ml.math.impls.matrix.RandomMatrix;
+import org.apache.ignite.ml.math.impls.matrix.SparseLocalOnHeapMatrix;
 import org.apache.ignite.ml.math.impls.vector.DenseLocalOnHeapVector;
 
 /**
@@ -116,6 +118,18 @@ public class MatrixUtil {
     }
 
     /** */
+    public static DenseLocalOnHeapMatrix asDense(SparseLocalOnHeapMatrix m, int acsMode) {
+        DenseLocalOnHeapMatrix res = new DenseLocalOnHeapMatrix(m.rowSize(), m.columnSize(), acsMode);
+
+        for (Integer row : m.indexesMap().keySet()) {
+            for (Integer col : m.indexesMap().get(row))
+                res.set(row, col, m.get(row, col));
+        }
+
+        return res;
+    }
+
+    /** */
     private static boolean isCopyLikeSupport(Matrix matrix) {
         return matrix instanceof RandomMatrix || matrix instanceof MatrixView || matrix instanceof CacheMatrix ||
             matrix instanceof PivotedMatrixView;
@@ -152,4 +166,38 @@ public class MatrixUtil {
 
         return res;
     }
+
+    /** */
+    public static double[][] unflatten(double[] fArr, int colsCnt) {
+        int rowsCnt = fArr.length / colsCnt;
+
+        double[][] res = new double[rowsCnt][colsCnt];
+
+        for (int i = 0; i < rowsCnt; i++)
+            for (int j = 0; j < colsCnt; j++)
+                res[i][j] = fArr[i * colsCnt + j];
+
+        return res;
+    }
+
+    /** */
+    public static double[] flatten(double[][] arr, int acsMode) {
+        assert arr != null;
+        assert arr[0] != null;
+
+        int size = arr.length * arr[0].length;
+        int rows = acsMode == StorageConstants.ROW_STORAGE_MODE ? arr.length : arr[0].length;
+        int cols = size / rows;
+
+        double[] res = new double[size];
+
+        int iLim = acsMode == StorageConstants.ROW_STORAGE_MODE ? rows : cols;
+        int jLim = acsMode == StorageConstants.ROW_STORAGE_MODE ? cols : rows;
+
+        for (int i = 0; i < iLim; i++)
+            for (int j = 0; j < jLim; j++)
+                res[i * jLim + j] = arr[i][j];
+
+        return res;
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/de259fff/modules/ml/src/test/java/org/apache/ignite/ml/clustering/KMeansDistributedClustererTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/clustering/KMeansDistributedClustererTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/clustering/KMeansDistributedClustererTest.java
index cdc2651..a59b7f9 100644
--- a/modules/ml/src/test/java/org/apache/ignite/ml/clustering/KMeansDistributedClustererTest.java
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/clustering/KMeansDistributedClustererTest.java
@@ -130,8 +130,8 @@ public class KMeansDistributedClustererTest extends GridCommonAbstractTest {
         Vector[] mc = new Vector[centersCnt];
         Arrays.fill(mc, VectorUtils.zeroes(2));
 
-        int centIndex = 0;
-        int totalCount = 0;
+        int centIdx = 0;
+        int totalCnt = 0;
 
         List<Vector> massCenters = new ArrayList<>();
 
@@ -140,12 +140,12 @@ public class KMeansDistributedClustererTest extends GridCommonAbstractTest {
                 DenseLocalOnHeapVector pnt = (DenseLocalOnHeapVector)new DenseLocalOnHeapVector(2).assign(centers.get(count));
                 // pertrubate point on random value.
                 pnt.map(val -> val + rnd.nextDouble() * squareSideLen / 100);
-                mc[centIndex] = mc[centIndex].plus(pnt);
-                points.assignRow(permutation.get(totalCount), pnt);
-                totalCount++;
+                mc[centIdx] = mc[centIdx].plus(pnt);
+                points.assignRow(permutation.get(totalCnt), pnt);
+                totalCnt++;
             }
-            massCenters.add(mc[centIndex].times(1 / (double)count));
-            centIndex++;
+            massCenters.add(mc[centIdx].times(1 / (double)count));
+            centIdx++;
         }
 
         EuclideanDistance dist = new EuclideanDistance();
@@ -169,6 +169,7 @@ public class KMeansDistributedClustererTest extends GridCommonAbstractTest {
         /** */
         List<Vector> orderedNodes;
 
+        /** */
         public OrderedNodesComparator(Vector[] orderedNodes, DistanceMeasure measure) {
             this.orderedNodes = Arrays.asList(orderedNodes);
             this.measure = measure;