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/ignite-5757 Commit: de259fffb7fa5c0f8f6f7eeb84b86f296fe3bde9 Parents: 1318472 Author: Yury Babak <[email protected]> Authored: Tue Jul 25 20:19:27 2017 +0300 Committer: Igor Sapego <[email protected]> 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;
