You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ag...@apache.org on 2017/04/18 09:00:30 UTC
[18/50] [abbrv] ignite git commit: IGNITE-5000 Rename Ignite Math
module to Ignite ML module
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/decompositions/LUDecomposition.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/decompositions/LUDecomposition.java b/modules/ml/src/main/java/org/apache/ignite/math/decompositions/LUDecomposition.java
new file mode 100644
index 0000000..82c90ec
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/decompositions/LUDecomposition.java
@@ -0,0 +1,366 @@
+/*
+ * 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.math.decompositions;
+
+import org.apache.ignite.math.Matrix;
+import org.apache.ignite.math.Vector;
+import org.apache.ignite.math.exceptions.CardinalityException;
+import org.apache.ignite.math.exceptions.SingularMatrixException;
+
+/**
+ * Calculates the LU-decomposition of a square matrix.
+ *
+ * This class inspired by class from Apache Common Math with similar name.
+ *
+ * @see <a href="http://mathworld.wolfram.com/LUDecomposition.html">MathWorld</a>
+ * @see <a href="http://en.wikipedia.org/wiki/LU_decomposition">Wikipedia</a>
+ */
+public class LUDecomposition extends DecompositionSupport {
+ /** Default bound to determine effective singularity in LU decomposition. */
+ private static final double DEFAULT_TOO_SMALL = 1e-11;
+
+ /** Pivot permutation associated with LU decomposition. */
+ private final Vector pivot;
+ /** Parity of the permutation associated with the LU decomposition. */
+ private boolean even;
+ /** Singularity indicator. */
+ private boolean singular;
+ /** Cached value of L. */
+ private Matrix cachedL;
+ /** Cached value of U. */
+ private Matrix cachedU;
+ /** Cached value of P. */
+ private Matrix cachedP;
+ /** Original matrix. */
+ private Matrix matrix;
+ /** Entries of LU decomposition. */
+ private Matrix lu;
+
+ /**
+ * Calculates the LU-decomposition of the given matrix.
+ * This constructor uses 1e-11 as default value for the singularity
+ * threshold.
+ *
+ * @param matrix Matrix to decompose.
+ * @throws CardinalityException if matrix is not square.
+ */
+ public LUDecomposition(Matrix matrix) {
+ this(matrix, DEFAULT_TOO_SMALL);
+ }
+
+ /**
+ * Calculates the LUP-decomposition of the given matrix.
+ *
+ * @param matrix Matrix to decompose.
+ * @param singularityThreshold threshold (based on partial row norm).
+ * @throws CardinalityException if matrix is not square.
+ */
+ public LUDecomposition(Matrix matrix, double singularityThreshold) {
+ assert matrix != null;
+
+ int rows = matrix.rowSize();
+ int cols = matrix.columnSize();
+
+ if (rows != cols)
+ throw new CardinalityException(rows, cols);
+
+ this.matrix = matrix;
+
+ lu = copy(matrix);
+
+ pivot = likeVector(matrix);
+
+ for (int i = 0; i < pivot.size(); i++)
+ pivot.setX(i, i);
+
+ even = true;
+ singular = false;
+
+ cachedL = null;
+ cachedU = null;
+ cachedP = null;
+
+ for (int col = 0; col < cols; col++) {
+
+ //upper
+ for (int row = 0; row < col; row++) {
+ Vector luRow = lu.viewRow(row);
+ double sum = luRow.get(col);
+
+ for (int i = 0; i < row; i++)
+ sum -= luRow.getX(i) * lu.getX(i, col);
+
+ luRow.setX(col, sum);
+ }
+
+ // permutation row
+ int max = col;
+
+ double largest = Double.NEGATIVE_INFINITY;
+
+ // lower
+ for (int row = col; row < rows; row++) {
+ Vector luRow = lu.viewRow(row);
+ double sum = luRow.getX(col);
+
+ for (int i = 0; i < col; i++)
+ sum -= luRow.getX(i) * lu.getX(i, col);
+
+ luRow.setX(col, sum);
+
+ if (Math.abs(sum) > largest) {
+ largest = Math.abs(sum);
+ max = row;
+ }
+ }
+
+ // Singularity check
+ if (Math.abs(lu.getX(max, col)) < singularityThreshold) {
+ singular = true;
+ return;
+ }
+
+ // Pivot if necessary
+ if (max != col) {
+ double tmp;
+ Vector luMax = lu.viewRow(max);
+ Vector luCol = lu.viewRow(col);
+
+ for (int i = 0; i < cols; i++) {
+ tmp = luMax.getX(i);
+ luMax.setX(i, luCol.getX(i));
+ luCol.setX(i, tmp);
+ }
+
+ int temp = (int)pivot.getX(max);
+ pivot.setX(max, pivot.getX(col));
+ pivot.setX(col, temp);
+
+ even = !even;
+ }
+
+ // Divide the lower elements by the "winning" diagonal elt.
+ final double luDiag = lu.getX(col, col);
+
+ for (int row = col + 1; row < cols; row++) {
+ double val = lu.getX(row, col) / luDiag;
+ lu.setX(row, col, val);
+ }
+ }
+ }
+
+ /**
+ * Destroys decomposition components and other internal components of decomposition.
+ */
+ @Override public void destroy() {
+ if (cachedL != null)
+ cachedL.destroy();
+ if (cachedU != null)
+ cachedU.destroy();
+ if (cachedP != null)
+ cachedP.destroy();
+ lu.destroy();
+ }
+
+ /**
+ * Returns the matrix L of the decomposition.
+ * <p>L is a lower-triangular matrix</p>
+ *
+ * @return the L matrix (or null if decomposed matrix is singular).
+ */
+ public Matrix getL() {
+ if ((cachedL == null) && !singular) {
+ final int m = pivot.size();
+
+ cachedL = like(matrix);
+ cachedL.assign(0.0);
+
+ for (int i = 0; i < m; ++i) {
+ for (int j = 0; j < i; ++j)
+ cachedL.setX(i, j, lu.getX(i, j));
+
+ cachedL.setX(i, i, 1.0);
+ }
+ }
+
+ return cachedL;
+ }
+
+ /**
+ * Returns the matrix U of the decomposition.
+ * <p>U is an upper-triangular matrix</p>
+ *
+ * @return the U matrix (or null if decomposed matrix is singular).
+ */
+ public Matrix getU() {
+ if ((cachedU == null) && !singular) {
+ final int m = pivot.size();
+
+ cachedU = like(matrix);
+ cachedU.assign(0.0);
+
+ for (int i = 0; i < m; ++i)
+ for (int j = i; j < m; ++j)
+ cachedU.setX(i, j, lu.getX(i, j));
+ }
+
+ return cachedU;
+ }
+
+ /**
+ * Returns the P rows permutation matrix.
+ * <p>P is a sparse matrix with exactly one element set to 1.0 in
+ * each row and each column, all other elements being set to 0.0.</p>
+ * <p>The positions of the 1 elements are given by the {@link #getPivot()
+ * pivot permutation vector}.</p>
+ *
+ * @return the P rows permutation matrix (or null if decomposed matrix is singular).
+ * @see #getPivot()
+ */
+ public Matrix getP() {
+ if ((cachedP == null) && !singular) {
+ final int m = pivot.size();
+
+ cachedP = like(matrix);
+ cachedP.assign(0.0);
+
+ for (int i = 0; i < m; ++i)
+ cachedP.setX(i, (int)pivot.get(i), 1.0);
+ }
+
+ return cachedP;
+ }
+
+ /**
+ * Returns the pivot permutation vector.
+ *
+ * @return the pivot permutation vector.
+ * @see #getP()
+ */
+ public Vector getPivot() {
+ return pivot.copy();
+ }
+
+ /**
+ * Return the determinant of the matrix.
+ *
+ * @return determinant of the matrix.
+ */
+ public double determinant() {
+ if (singular)
+ return 0;
+
+ final int m = pivot.size();
+ double determinant = even ? 1 : -1;
+
+ for (int i = 0; i < m; i++)
+ determinant *= lu.getX(i, i);
+
+ return determinant;
+ }
+
+ /** */
+ public Vector solve(Vector b) {
+ final int m = pivot.size();
+
+ if (b.size() != m)
+ throw new CardinalityException(b.size(), m);
+
+ if (singular)
+ throw new SingularMatrixException();
+
+ final double[] bp = new double[m];
+
+ // Apply permutations to b
+ for (int row = 0; row < m; row++)
+ bp[row] = b.get((int)pivot.get(row));
+
+ // Solve LY = b
+ for (int col = 0; col < m; col++) {
+ final double bpCol = bp[col];
+
+ for (int i = col + 1; i < m; i++)
+ bp[i] -= bpCol * lu.get(i, col);
+ }
+
+ // Solve UX = Y
+ for (int col = m - 1; col >= 0; col--) {
+ bp[col] /= lu.get(col, col);
+ final double bpCol = bp[col];
+
+ for (int i = 0; i < col; i++)
+ bp[i] -= bpCol * lu.get(i, col);
+ }
+
+ return b.like(m).assign(bp);
+ }
+
+ /** */
+ public Matrix solve(Matrix b) {
+ final int m = pivot.size();
+
+ if (b.rowSize() != m)
+ throw new CardinalityException(b.rowSize(), m);
+
+ if (singular)
+ throw new SingularMatrixException();
+
+ final int nColB = b.columnSize();
+
+ // Apply permutations to b
+ final double[][] bp = new double[m][nColB];
+ for (int row = 0; row < m; row++) {
+ final double[] bpRow = bp[row];
+ final int pRow = (int)pivot.get(row);
+
+ for (int col = 0; col < nColB; col++)
+ bpRow[col] = b.get(pRow, col);
+ }
+
+ // Solve LY = b
+ for (int col = 0; col < m; col++) {
+ final double[] bpCol = bp[col];
+ for (int i = col + 1; i < m; i++) {
+ final double[] bpI = bp[i];
+ final double luICol = lu.get(i, col);
+
+ for (int j = 0; j < nColB; j++)
+ bpI[j] -= bpCol[j] * luICol;
+ }
+ }
+
+ // Solve UX = Y
+ for (int col = m - 1; col >= 0; col--) {
+ final double[] bpCol = bp[col];
+ final double luDiag = lu.getX(col, col);
+
+ for (int j = 0; j < nColB; j++)
+ bpCol[j] /= luDiag;
+
+ for (int i = 0; i < col; i++) {
+ final double[] bpI = bp[i];
+ final double luICol = lu.get(i, col);
+
+ for (int j = 0; j < nColB; j++)
+ bpI[j] -= bpCol[j] * luICol;
+ }
+ }
+
+ return b.like(b.rowSize(), b.columnSize()).assign(bp);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/decompositions/QRDecomposition.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/decompositions/QRDecomposition.java b/modules/ml/src/main/java/org/apache/ignite/math/decompositions/QRDecomposition.java
new file mode 100644
index 0000000..9608ed5
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/decompositions/QRDecomposition.java
@@ -0,0 +1,186 @@
+/*
+ * 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.math.decompositions;
+
+import org.apache.ignite.math.Matrix;
+import org.apache.ignite.math.Vector;
+import org.apache.ignite.math.functions.Functions;
+
+/**
+ * For an {@code m x n} matrix {@code A} with {@code m >= n}, the QR decomposition
+ * is an {@code m x n} orthogonal matrix {@code Q} and an {@code n x n} upper
+ * triangular matrix {@code R} so that {@code A = Q*R}.
+ */
+public class QRDecomposition extends DecompositionSupport {
+ /** */
+ private final Matrix q;
+ /** */
+ private final Matrix r;
+
+ /** */
+ private final Matrix mType;
+ /** */
+ private final boolean fullRank;
+
+ /** */
+ private final int rows;
+ /** */
+ private final int cols;
+
+ /**
+ * @param v Value to be checked for being an ordinary double.
+ */
+ private void checkDouble(double v) {
+ if (Double.isInfinite(v) || Double.isNaN(v))
+ throw new ArithmeticException("Invalid intermediate result");
+ }
+
+ /**
+ * Constructs a new QR decomposition object computed by Householder reflections.
+ *
+ * @param mtx A rectangular matrix.
+ */
+ public QRDecomposition(Matrix mtx) {
+ assert mtx != null;
+
+ rows = mtx.rowSize();
+
+ int min = Math.min(mtx.rowSize(), mtx.columnSize());
+
+ cols = mtx.columnSize();
+
+ mType = like(mtx, 1, 1);
+
+ Matrix qTmp = copy(mtx);
+
+ boolean fullRank = true;
+
+ r = like(mtx, min, cols);
+
+ for (int i = 0; i < min; i++) {
+ Vector qi = qTmp.viewColumn(i);
+
+ double alpha = qi.kNorm(2);
+
+ if (Math.abs(alpha) > Double.MIN_VALUE)
+ qi.map(Functions.div(alpha));
+ else {
+ checkDouble(alpha);
+
+ fullRank = false;
+ }
+
+ r.set(i, i, alpha);
+
+ for (int j = i + 1; j < cols; j++) {
+ Vector qj = qTmp.viewColumn(j);
+
+ double norm = qj.kNorm(2);
+
+ if (Math.abs(norm) > Double.MIN_VALUE) {
+ double beta = qi.dot(qj);
+
+ r.set(i, j, beta);
+
+ if (j < min)
+ qj.map(qi, Functions.plusMult(-beta));
+ }
+ else
+ checkDouble(norm);
+ }
+ }
+
+ if (cols > min)
+ q = qTmp.viewPart(0, rows, 0, min).copy();
+ else
+ q = qTmp;
+
+ this.fullRank = fullRank;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void destroy() {
+ q.destroy();
+ r.destroy();
+ mType.destroy();
+ }
+
+ /**
+ * Gets orthogonal factor {@code Q}.
+ */
+ public Matrix getQ() {
+ return q;
+ }
+
+ /**
+ * Gets triangular factor {@code R}.
+ */
+ public Matrix getR() {
+ return r;
+ }
+
+ /**
+ * Returns whether the matrix {@code A} has full rank.
+ *
+ * @return true if {@code R}, and hence {@code A} , has full rank.
+ */
+ public boolean hasFullRank() {
+ return fullRank;
+ }
+
+ /**
+ * Least squares solution of {@code A*X = B}; {@code returns X}.
+ *
+ * @param mtx A matrix with as many rows as {@code A} and any number of cols.
+ * @return {@code X<} that minimizes the two norm of {@code Q*R*X - B}.
+ * @throws IllegalArgumentException if {@code B.rows() != A.rows()}.
+ */
+ public Matrix solve(Matrix mtx) {
+ if (mtx.rowSize() != rows)
+ throw new IllegalArgumentException("Matrix row dimensions must agree.");
+
+ int cols = mtx.columnSize();
+
+ Matrix x = like(mType, this.cols, cols);
+
+ Matrix qt = getQ().transpose();
+ Matrix y = qt.times(mtx);
+
+ Matrix r = getR();
+
+ for (int k = Math.min(this.cols, rows) - 1; k > 0; k--) {
+ // X[k,] = Y[k,] / R[k,k], note that X[k,] starts with 0 so += is same as =
+ x.viewRow(k).map(y.viewRow(k), Functions.plusMult(1 / r.get(k, k)));
+
+ // Y[0:(k-1),] -= R[0:(k-1),k] * X[k,]
+ Vector rCol = r.viewColumn(k).viewPart(0, k);
+
+ for (int c = 0; c < cols; c++)
+ y.viewColumn(c).viewPart(0, k).map(rCol, Functions.plusMult(-x.get(k, c)));
+ }
+
+ return x;
+ }
+
+ /**
+ * Returns a rough string rendition of a QR.
+ */
+ @Override public String toString() {
+ return String.format("QR(%d x %d, fullRank=%s)", rows, cols, hasFullRank());
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/decompositions/SingularValueDecomposition.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/decompositions/SingularValueDecomposition.java b/modules/ml/src/main/java/org/apache/ignite/math/decompositions/SingularValueDecomposition.java
new file mode 100644
index 0000000..75eb206
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/decompositions/SingularValueDecomposition.java
@@ -0,0 +1,620 @@
+/*
+ * 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.math.decompositions;
+
+import org.apache.ignite.math.Algebra;
+import org.apache.ignite.math.Matrix;
+
+/**
+ * Compute a singular value decomposition (SVD) of {@code (l x k)} matrix {@code m}.
+ * <p>This decomposition can be thought
+ * as an extension of {@link EigenDecomposition} to rectangular matrices. The factorization we get is following:</p>
+ * <p>{@code m = u * s * v^{*}}, where</p>
+ * <ul><li>{@code u} is a real or complex unitary matrix.</li>
+ * <li>{@code s} is a rectangular diagonal matrix with non-negative real numbers on diagonal
+ * (these numbers are singular values of {@code m}).</li>
+ * <li>{@code v} is a real or complex unitary matrix.</li></ul>
+ * <p>If {@code m} is real then {@code u} and {@code v} are also real.</p>
+ * <p>See also: <a href="https://en.wikipedia.org/wiki/Singular_value_decomposition">Wikipedia article on SVD</a>.</p>
+ * <p>Note: complex case is currently not supported.</p>
+ */
+public class SingularValueDecomposition extends DecompositionSupport {
+ // U and V.
+ /** */
+ private final double[][] u;
+ /** */
+ private final double[][] v;
+
+ /** Singular values. */
+ private final double[] s;
+
+ /** Row dimension. */
+ private final int m;
+ /** Column dimension. */
+ private final int n;
+
+ /** */
+ private Matrix arg;
+
+ /** */
+ private boolean transpositionNeeded;
+
+ /**
+ * Singular value decomposition object.
+ *
+ * @param arg A rectangular matrix.
+ */
+ public SingularValueDecomposition(Matrix arg) {
+ assert arg != null;
+
+ this.arg = arg;
+
+ if (arg.rowSize() < arg.columnSize())
+ transpositionNeeded = true;
+
+ double[][] a;
+
+ if (transpositionNeeded) {
+ // Use the transpose matrix.
+ m = arg.columnSize();
+ n = arg.rowSize();
+
+ a = new double[m][n];
+
+ for (int i = 0; i < m; i++)
+ for (int j = 0; j < n; j++)
+ a[i][j] = arg.get(j, i);
+ }
+ else {
+ m = arg.rowSize();
+ n = arg.columnSize();
+
+ a = new double[m][n];
+
+ for (int i = 0; i < m; i++)
+ for (int j = 0; j < n; j++)
+ a[i][j] = arg.get(i, j);
+ }
+
+ int nu = Math.min(m, n);
+
+ s = new double[Math.min(m + 1, n)];
+ u = new double[m][nu];
+ v = new double[n][n];
+
+ double[] e = new double[n];
+ double[] work = new double[m];
+
+ int nct = Math.min(m - 1, n);
+ int nrt = Math.max(0, Math.min(n - 2, m));
+
+ for (int k = 0; k < Math.max(nct, nrt); k++) {
+ if (k < nct) {
+ // Compute the transformation for the k-th column and
+ // place the k-th diagonal in s[k]. Compute 2-norm of k-th
+ // column without under/overflow.
+ s[k] = 0;
+
+ for (int i = k; i < m; i++)
+ s[k] = Algebra.hypot(s[k], a[i][k]);
+
+ if (s[k] != 0.0) {
+ if (a[k][k] < 0.0)
+ s[k] = -s[k];
+
+ for (int i = k; i < m; i++)
+ a[i][k] /= s[k];
+
+ a[k][k] += 1.0;
+ }
+
+ s[k] = -s[k];
+ }
+
+ for (int j = k + 1; j < n; j++) {
+ if (k < nct && s[k] != 0.0) {
+ // Apply the transformation.
+ double t = 0;
+
+ for (int i = k; i < m; i++)
+ t += a[i][k] * a[i][j];
+
+ t = -t / a[k][k];
+
+ for (int i = k; i < m; i++)
+ a[i][j] += t * a[i][k];
+ }
+
+ // Place the k-th row of A into e for the
+ // subsequent calculation of the row transformation.
+ e[j] = a[k][j];
+ }
+
+ if (k < nct)
+ // Place the transformation in U for subsequent back
+ // multiplication.
+ for (int i = k; i < m; i++)
+ u[i][k] = a[i][k];
+
+ if (k < nrt) {
+ // Compute the k-th row transformation and place the
+ // k-th super-diagonal in e[k].
+ // Compute 2-norm without under/overflow.
+ e[k] = 0;
+
+ for (int i = k + 1; i < n; i++)
+ e[k] = Algebra.hypot(e[k], e[i]);
+
+ if (e[k] != 0.0) {
+ if (e[k + 1] < 0.0)
+ e[k] = -e[k];
+
+ for (int i = k + 1; i < n; i++)
+ e[i] /= e[k];
+
+ e[k + 1] += 1.0;
+ }
+
+ e[k] = -e[k];
+
+ if (k + 1 < m && e[k] != 0.0) {
+ // Apply the transformation.
+ for (int i = k + 1; i < m; i++)
+ work[i] = 0.0;
+
+ for (int j = k + 1; j < n; j++)
+ for (int i = k + 1; i < m; i++)
+ work[i] += e[j] * a[i][j];
+
+ for (int j = k + 1; j < n; j++) {
+ double t = -e[j] / e[k + 1];
+
+ for (int i = k + 1; i < m; i++)
+ a[i][j] += t * work[i];
+ }
+ }
+
+ // Place the transformation in V for subsequent
+ // back multiplication.
+ for (int i = k + 1; i < n; i++)
+ v[i][k] = e[i];
+ }
+ }
+
+ // Set up the final bi-diagonal matrix or order p.
+ int p = Math.min(n, m + 1);
+
+ if (nct < n)
+ s[nct] = a[nct][nct];
+
+ if (m < p)
+ s[p - 1] = 0.0;
+
+ if (nrt + 1 < p)
+ e[nrt] = a[nrt][p - 1];
+
+ e[p - 1] = 0.0;
+
+ // Generate U.
+ for (int j = nct; j < nu; j++) {
+ for (int i = 0; i < m; i++)
+ u[i][j] = 0.0;
+
+ u[j][j] = 1.0;
+ }
+
+ for (int k = nct - 1; k >= 0; k--) {
+ if (s[k] != 0.0) {
+ for (int j = k + 1; j < nu; j++) {
+ double t = 0;
+
+ for (int i = k; i < m; i++)
+ t += u[i][k] * u[i][j];
+
+ t = -t / u[k][k];
+
+ for (int i = k; i < m; i++)
+ u[i][j] += t * u[i][k];
+ }
+
+ for (int i = k; i < m; i++)
+ u[i][k] = -u[i][k];
+
+ u[k][k] = 1.0 + u[k][k];
+
+ for (int i = 0; i < k - 1; i++)
+ u[i][k] = 0.0;
+ }
+ else {
+ for (int i = 0; i < m; i++)
+ u[i][k] = 0.0;
+
+ u[k][k] = 1.0;
+ }
+ }
+
+ // Generate V.
+ for (int k = n - 1; k >= 0; k--) {
+ if (k < nrt && e[k] != 0.0) {
+ for (int j = k + 1; j < nu; j++) {
+ double t = 0;
+
+ for (int i = k + 1; i < n; i++)
+ t += v[i][k] * v[i][j];
+
+ t = -t / v[k + 1][k];
+
+ for (int i = k + 1; i < n; i++)
+ v[i][j] += t * v[i][k];
+ }
+ }
+
+ for (int i = 0; i < n; i++)
+ v[i][k] = 0.0;
+
+ v[k][k] = 1.0;
+ }
+
+ // Main iteration loop for the singular values.
+ int pp = p - 1;
+ int iter = 0;
+
+ double eps = Math.pow(2.0, -52.0);
+ double tiny = Math.pow(2.0, -966.0);
+
+ while (p > 0) {
+ int k;
+
+ for (k = p - 2; k >= -1; k--) {
+ if (k == -1)
+ break;
+
+ if (Math.abs(e[k]) <= tiny + eps * (Math.abs(s[k]) + Math.abs(s[k + 1]))) {
+ e[k] = 0.0;
+
+ break;
+ }
+ }
+
+ int kase;
+
+ if (k == p - 2)
+ kase = 4;
+ else {
+ int ks;
+
+ for (ks = p - 1; ks >= k; ks--) {
+ if (ks == k)
+ break;
+
+ double t =
+ (ks != p ? Math.abs(e[ks]) : 0.) +
+ (ks != k + 1 ? Math.abs(e[ks - 1]) : 0.);
+
+ if (Math.abs(s[ks]) <= tiny + eps * t) {
+ s[ks] = 0.0;
+
+ break;
+ }
+ }
+
+ if (ks == k)
+ kase = 3;
+ else if (ks == p - 1)
+ kase = 1;
+ else {
+ kase = 2;
+
+ k = ks;
+ }
+ }
+
+ k++;
+
+ // Perform the task indicated by kase.
+ switch (kase) {
+ // Deflate negligible s(p).
+ case 1: {
+ double f = e[p - 2];
+
+ e[p - 2] = 0.0;
+
+ for (int j = p - 2; j >= k; j--) {
+ double t = Algebra.hypot(s[j], f);
+ double cs = s[j] / t;
+ double sn = f / t;
+
+ s[j] = t;
+
+ if (j != k) {
+ f = -sn * e[j - 1];
+ e[j - 1] = cs * e[j - 1];
+ }
+
+ for (int i = 0; i < n; i++) {
+ t = cs * v[i][j] + sn * v[i][p - 1];
+
+ v[i][p - 1] = -sn * v[i][j] + cs * v[i][p - 1];
+ v[i][j] = t;
+ }
+ }
+ }
+
+ break;
+
+ // Split at negligible s(k).
+ case 2: {
+ double f = e[k - 1];
+ e[k - 1] = 0.0;
+
+ for (int j = k; j < p; j++) {
+ double t = Algebra.hypot(s[j], f);
+ double cs = s[j] / t;
+ double sn = f / t;
+
+ s[j] = t;
+ f = -sn * e[j];
+ e[j] = cs * e[j];
+
+ for (int i = 0; i < m; i++) {
+ t = cs * u[i][j] + sn * u[i][k - 1];
+
+ u[i][k - 1] = -sn * u[i][j] + cs * u[i][k - 1];
+ u[i][j] = t;
+ }
+ }
+ }
+
+ break;
+
+ // Perform one qr step.
+ case 3: {
+ // Calculate the shift.
+ double scale = Math.max(Math.max(Math.max(Math.max(
+ Math.abs(s[p - 1]), Math.abs(s[p - 2])), Math.abs(e[p - 2])),
+ Math.abs(s[k])), Math.abs(e[k]));
+
+ double sp = s[p - 1] / scale;
+ double spm1 = s[p - 2] / scale;
+ double epm1 = e[p - 2] / scale;
+ double sk = s[k] / scale;
+ double ek = e[k] / scale;
+ double b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0;
+ double c = sp * epm1 * sp * epm1;
+ double shift = 0.0;
+
+ if (b != 0.0 || c != 0.0) {
+ shift = Math.sqrt(b * b + c);
+
+ if (b < 0.0)
+ shift = -shift;
+
+ shift = c / (b + shift);
+ }
+
+ double f = (sk + sp) * (sk - sp) + shift;
+ double g = sk * ek;
+
+ // Chase zeros.
+ for (int j = k; j < p - 1; j++) {
+ double t = Algebra.hypot(f, g);
+ double cs = f / t;
+ double sn = g / t;
+
+ if (j != k)
+ e[j - 1] = t;
+
+ f = cs * s[j] + sn * e[j];
+ e[j] = cs * e[j] - sn * s[j];
+ g = sn * s[j + 1];
+ s[j + 1] = cs * s[j + 1];
+
+ for (int i = 0; i < n; i++) {
+ t = cs * v[i][j] + sn * v[i][j + 1];
+
+ v[i][j + 1] = -sn * v[i][j] + cs * v[i][j + 1];
+ v[i][j] = t;
+ }
+
+ t = Algebra.hypot(f, g);
+ cs = f / t;
+ sn = g / t;
+ s[j] = t;
+ f = cs * e[j] + sn * s[j + 1];
+ s[j + 1] = -sn * e[j] + cs * s[j + 1];
+ g = sn * e[j + 1];
+ e[j + 1] = cs * e[j + 1];
+
+ if (j < m - 1)
+ for (int i = 0; i < m; i++) {
+ t = cs * u[i][j] + sn * u[i][j + 1];
+
+ u[i][j + 1] = -sn * u[i][j] + cs * u[i][j + 1];
+ u[i][j] = t;
+ }
+ }
+
+ e[p - 2] = f;
+ iter = iter + 1;
+ }
+
+ break;
+
+ // Convergence.
+ case 4: {
+ // Make the singular values positive.
+ if (s[k] <= 0.0) {
+ s[k] = s[k] < 0.0 ? -s[k] : 0.0;
+
+ for (int i = 0; i <= pp; i++)
+ v[i][k] = -v[i][k];
+ }
+
+ // Order the singular values.
+ while (k < pp) {
+ if (s[k] >= s[k + 1])
+ break;
+
+ double t = s[k];
+
+ s[k] = s[k + 1];
+ s[k + 1] = t;
+
+ if (k < n - 1)
+ for (int i = 0; i < n; i++) {
+ t = v[i][k + 1];
+
+ v[i][k + 1] = v[i][k];
+ v[i][k] = t;
+ }
+
+ if (k < m - 1)
+ for (int i = 0; i < m; i++) {
+ t = u[i][k + 1];
+
+ u[i][k + 1] = u[i][k];
+ u[i][k] = t;
+ }
+
+ k++;
+ }
+
+ iter = 0;
+ p--;
+ }
+
+ break;
+
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }
+
+ /**
+ * Gets the two norm condition number, which is {@code max(S) / min(S)} .
+ */
+ public double cond() {
+ return s[0] / s[Math.min(m, n) - 1];
+ }
+
+ /**
+ * @return the diagonal matrix of singular values.
+ */
+ public Matrix getS() {
+ double[][] s = new double[n][n];
+
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++)
+ s[i][j] = 0.0;
+
+ s[i][i] = this.s[i];
+ }
+
+ return like(arg, n, n).assign(s);
+ }
+
+ /**
+ * Gets the diagonal of {@code S}, which is a one-dimensional array of
+ * singular values.
+ *
+ * @return diagonal of {@code S}.
+ */
+ public double[] getSingularValues() {
+ return s;
+ }
+
+ /**
+ * Gets the left singular vectors {@code U}.
+ *
+ * @return {@code U}
+ */
+ public Matrix getU() {
+ if (transpositionNeeded)
+ return like(arg, v.length, v.length).assign(v);
+ else {
+ int numCols = Math.min(m + 1, n);
+
+ Matrix r = like(arg, m, numCols);
+
+ for (int i = 0; i < m; i++)
+ for (int j = 0; j < numCols; j++)
+ r.set(i, j, u[i][j]);
+
+ return r;
+ }
+ }
+
+ /**
+ * Gets the right singular vectors {@code V}.
+ *
+ * @return {@code V}
+ */
+ public Matrix getV() {
+ if (transpositionNeeded) {
+ int numCols = Math.min(m + 1, n);
+
+ Matrix r = like(arg, m, numCols);
+
+ for (int i = 0; i < m; i++)
+ for (int j = 0; j < numCols; j++)
+ r.set(i, j, u[i][j]);
+
+ return r;
+ }
+ else
+ return like(arg, v.length, v.length).assign(v);
+ }
+
+ /**
+ * Gets the two norm, which is {@code max(S)}.
+ */
+ public double norm2() {
+ return s[0];
+ }
+
+ /**
+ * Gets effective numerical matrix rank.
+ */
+ public int rank() {
+ double eps = Math.pow(2.0, -52.0);
+ double tol = Math.max(m, n) * s[0] * eps;
+ int r = 0;
+
+ for (double value : s)
+ if (value > tol)
+ r++;
+
+ return r;
+ }
+
+ /**
+ * Gets [n � n] covariance matrix.
+ *
+ * @param minSingularVal Value below which singular values are ignored.
+ */
+ Matrix getCovariance(double minSingularVal) {
+ Matrix j = like(arg, s.length, s.length);
+ Matrix vMat = like(arg, v.length, v.length).assign(v);
+
+ for (int i = 0; i < s.length; i++)
+ j.set(i, i, s[i] >= minSingularVal ? 1 / (s[i] * s[i]) : 0.0);
+
+ return vMat.times(j).times(vMat.transpose());
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/decompositions/package-info.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/decompositions/package-info.java b/modules/ml/src/main/java/org/apache/ignite/math/decompositions/package-info.java
new file mode 100644
index 0000000..dcfa0f8
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/decompositions/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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 description. -->
+ * Contains matrix decompositions for distributed code algebra.
+ */
+package org.apache.ignite.math.decompositions;
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/exceptions/CardinalityException.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/exceptions/CardinalityException.java b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/CardinalityException.java
new file mode 100644
index 0000000..fc87a27
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/CardinalityException.java
@@ -0,0 +1,38 @@
+/*
+ * 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.math.exceptions;
+
+import org.apache.ignite.IgniteException;
+
+/**
+ * Indicates a cardinality mismatch in matrix or vector operations.
+ */
+public class CardinalityException extends IgniteException {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Creates new cardinality violation exception.
+ *
+ * @param exp Expected cardinality.
+ * @param act Actual cardinality.
+ */
+ public CardinalityException(int exp, int act) {
+ super("Cardinality violation [expected=" + exp + ", actual=" + act + "]");
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/exceptions/ColumnIndexException.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/exceptions/ColumnIndexException.java b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/ColumnIndexException.java
new file mode 100644
index 0000000..7670caf
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/ColumnIndexException.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.math.exceptions;
+
+import org.apache.ignite.IgniteException;
+
+/**
+ * This exception is used to indicate any error condition accessing matrix elements by invalid column index.
+ */
+public class ColumnIndexException extends IgniteException {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * @param idx Index value that caused this exception.
+ */
+ public ColumnIndexException(int idx) {
+ super("Invalid (out of bound) column index: " + idx);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/exceptions/IndexException.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/exceptions/IndexException.java b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/IndexException.java
new file mode 100644
index 0000000..9ada706
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/IndexException.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.math.exceptions;
+
+import org.apache.ignite.IgniteException;
+
+/**
+ * Indicates an invalid, i.e. out of bound, index on matrix or vector operations.
+ */
+public class IndexException extends IgniteException {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * @param idx Index value that caused this exception.
+ */
+ public IndexException(int idx) {
+ super("Invalid (out of bound) index: " + idx);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/exceptions/NonPositiveDefiniteMatrixException.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/exceptions/NonPositiveDefiniteMatrixException.java b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/NonPositiveDefiniteMatrixException.java
new file mode 100644
index 0000000..b6017c2
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/NonPositiveDefiniteMatrixException.java
@@ -0,0 +1,20 @@
+package org.apache.ignite.math.exceptions;
+
+import org.apache.ignite.IgniteException;
+
+/**
+ * This exception is used to indicate error condition of matrix elements failing the positivity check.
+ */
+public class NonPositiveDefiniteMatrixException extends IgniteException {
+ /**
+ * Construct an exception.
+ *
+ * @param wrong Value that fails the positivity check.
+ * @param idx Row (and column) index.
+ * @param threshold Absolute positivity threshold.
+ */
+ public NonPositiveDefiniteMatrixException(double wrong, int idx, double threshold) {
+ super("Matrix must be positive, wrong element located on diagonal with index "
+ + idx + " and has value " + wrong + " with this threshold " + threshold);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/exceptions/NonSymmetricMatrixException.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/exceptions/NonSymmetricMatrixException.java b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/NonSymmetricMatrixException.java
new file mode 100644
index 0000000..8b4cbdb
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/NonSymmetricMatrixException.java
@@ -0,0 +1,18 @@
+package org.apache.ignite.math.exceptions;
+
+import org.apache.ignite.IgniteException;
+
+/**
+ * This exception is used to indicate error condition of matrix failing the symmetry check.
+ */
+public class NonSymmetricMatrixException extends IgniteException {
+ /**
+ * @param row Row.
+ * @param col Column.
+ * @param threshold Threshold.
+ */
+ public NonSymmetricMatrixException(int row, int col, double threshold) {
+ super("Symmetric matrix expected, the symmetry is broken on row "
+ + row + " and col " + col + " with this threshold " + threshold);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/exceptions/RowIndexException.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/exceptions/RowIndexException.java b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/RowIndexException.java
new file mode 100644
index 0000000..f74ae2c
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/RowIndexException.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.math.exceptions;
+
+import org.apache.ignite.IgniteException;
+
+/**
+ * This exception is used to indicate any error condition accessing matrix elements by invalid row index.
+ */
+public class RowIndexException extends IgniteException {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * @param idx Index value that caused this exception.
+ */
+ public RowIndexException(int idx) {
+ super("Invalid (out of bound) row index: " + idx);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/exceptions/SingularMatrixException.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/exceptions/SingularMatrixException.java b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/SingularMatrixException.java
new file mode 100644
index 0000000..4ed3410
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/SingularMatrixException.java
@@ -0,0 +1,30 @@
+/*
+ * 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.math.exceptions;
+
+import org.apache.ignite.IgniteException;
+
+/**
+ * Exception to be thrown when a non-singular matrix is expected.
+ */
+public class SingularMatrixException extends IgniteException {
+ /** */
+ public SingularMatrixException() {
+ super("Regular (or non-singular) matrix expected.");
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/exceptions/UnknownProviderException.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/exceptions/UnknownProviderException.java b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/UnknownProviderException.java
new file mode 100644
index 0000000..3e6498a
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/UnknownProviderException.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.math.exceptions;
+
+import org.apache.ignite.IgniteException;
+
+/**
+ * Indicates that no provider has been found for a given vector or matrix flavor.
+ */
+public class UnknownProviderException extends IgniteException {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * @param flv Flavor (a.k.a. operation performance hints) that has no registered provider for.
+ */
+ public UnknownProviderException(String flv) {
+ super("No provider has been found for the flavor: " + flv);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/exceptions/UnsupportedOperationException.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/exceptions/UnsupportedOperationException.java b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/UnsupportedOperationException.java
new file mode 100644
index 0000000..be5264c
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/UnsupportedOperationException.java
@@ -0,0 +1,44 @@
+/*
+ * 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.math.exceptions;
+
+import org.apache.ignite.IgniteException;
+
+/**
+ * Indicate that a specific operation is not supported by the underlying implementation.
+ * In some cases, an operation may be unsupported only in certain cases where, for example,
+ * it could not be deterministically completed in polynomial time.
+ */
+public class UnsupportedOperationException extends IgniteException {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * @param errMsg Error message.
+ */
+ public UnsupportedOperationException(String errMsg) {
+ super(errMsg);
+ }
+
+ /**
+ *
+ */
+ public UnsupportedOperationException() {
+ this("Unsupported operation.");
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/exceptions/package-info.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/exceptions/package-info.java b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/package-info.java
new file mode 100644
index 0000000..83f3fa4
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/exceptions/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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 description. -->
+ * Contains exceptions for distributed code algebra.
+ */
+package org.apache.ignite.math.exceptions;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/functions/Functions.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/functions/Functions.java b/modules/ml/src/main/java/org/apache/ignite/math/functions/Functions.java
new file mode 100644
index 0000000..7100908
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/functions/Functions.java
@@ -0,0 +1,136 @@
+/*
+ * 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.math.functions;
+
+/**
+ * Compatibility with Apache Mahout.
+ */
+public final class Functions {
+ /** Function that returns {@code Math.abs(a)}. */
+ public static final IgniteDoubleFunction<Double> ABS = Math::abs;
+
+ /** Function that returns its argument. */
+ public static final IgniteDoubleFunction<Double> IDENTITY = (a) -> a;
+
+ /** Function that returns {@code Math.log(a) / Math.log(2)}. */
+ public static final IgniteDoubleFunction<Double> LOG2 = (a) -> Math.log(a) * 1.4426950408889634;
+
+ /** Function that returns {@code -a}. */
+ public static final IgniteDoubleFunction<Double> NEGATE = (a) -> -a;
+
+ /** Function that returns {@code a < 0 ? -1 : a > 0 ? 1 : 0 }. */
+ public static final IgniteDoubleFunction<Double> SIGN = (a) -> a < 0.0 ? -1.0 : a > 0.0 ? 1.0 : 0.0;
+
+ /** Function that returns {@code a * a}. */
+ public static final IgniteDoubleFunction<Double> SQUARE = (a) -> a * a;
+
+ /** Function that returns {@code 1 / (1 + exp(-a) } */
+ public static final IgniteDoubleFunction<Double> SIGMOID = (a) -> 1.0 / (1.0 + Math.exp(-a));
+
+ /** Function that returns {@code 1 / a } */
+ public static final IgniteDoubleFunction<Double> INV = (a) -> 1.0 / a;
+
+ /** Function that returns {@code a * (1-a) } */
+ public static final IgniteDoubleFunction<Double> SIGMOIDGRADIENT = (a) -> a * (1.0 - a);
+
+ /** Function that returns {@code a % b}. */
+ public static final IgniteBiFunction<Double, Double, Double> MOD = (a, b) -> a % b;
+
+ /** Function that returns {@code a * b}. */
+ public static final IgniteBiFunction<Double, Double, Double> MULT = (a, b) -> a * b;
+
+ /** Function that returns {@code Math.log(a) / Math.log(b)}. */
+ public static final IgniteBiFunction<Double, Double, Double> LG = (a, b) -> Math.log(a) / Math.log(b);
+
+ /** Function that returns {@code a + b}. */
+ public static final IgniteBiFunction<Double, Double, Double> PLUS = (a, b) -> a + b;
+
+ /** Function that returns {@code a - b}. */
+ public static final IgniteBiFunction<Double, Double, Double> MINUS = (a, b) -> a - b;
+
+ /** Function that returns {@code abs(a - b)}. */
+ public static final IgniteBiFunction<Double, Double, Double> MINUS_ABS = (a, b) -> Math.abs(a - b);
+
+ /** Function that returns {@code max(abs(a), abs(b))}. */
+ public static final IgniteBiFunction<Double, Double, Double> MAX_ABS = (a, b) -> Math.max(Math.abs(a), Math.abs(b));
+
+ /** Function that returns {@code min(abs(a), abs(b))}. */
+ public static final IgniteBiFunction<Double, Double, Double> MIN_ABS = (a, b) -> Math.min(Math.abs(a), Math.abs(b));
+
+ /** Function that returns {@code Math.abs(a) + Math.abs(b)}. */
+ public static final IgniteBiFunction<Double, Double, Double> PLUS_ABS = (a, b) -> Math.abs(a) + Math.abs(b);
+
+ /** Function that returns {@code (a - b) * (a - b)} */
+ public static final IgniteBiFunction<Double, Double, Double> MINUS_SQUARED = (a, b) -> (a - b) * (a - b);
+
+ /**
+ * Function that returns {@code a < b ? -1 : a > b ? 1 : 0}.
+ */
+ public static final IgniteBiFunction<Double, Double, Double> COMPARE = (a, b) -> a < b ? -1.0 : a > b ? 1.0 : 0.0;
+
+ /**
+ * Function that returns {@code a + b}. {@code a} is a variable, {@code b} is fixed.
+ *
+ * @param b
+ */
+ public static IgniteDoubleFunction<Double> plus(final double b) {
+ return (a) -> a + b;
+ }
+
+ /**
+ * Function that returns {@code a * b}. {@code a} is a variable, {@code b} is fixed.
+ *
+ * @param b
+ */
+ public static IgniteDoubleFunction<Double> mult(final double b) {
+ return (a) -> a * b;
+ }
+
+ /** Function that returns {@code a / b}. {@code a} is a variable, {@code b} is fixed. */
+ public static IgniteDoubleFunction<Double> div(double b) {
+ return mult(1 / b);
+ }
+
+ /**
+ * Function that returns {@code a + b*constant}. {@code a} and {@code b} are variables,
+ * {@code constant} is fixed.
+ */
+ public static IgniteBiFunction<Double, Double, Double> plusMult(double constant) {
+ return (a, b) -> a + b * constant;
+ }
+
+ /**
+ * Function that returns {@code a - b*constant}. {@code a} and {@code b} are variables,
+ * {@code constant} is fixed.
+ */
+ public static IgniteBiFunction<Double, Double, Double> minusMult(double constant) {
+ return (a, b) -> a - b * constant;
+ }
+
+ /**
+ * @param b
+ */
+ public static IgniteDoubleFunction<Double> pow(final double b) {
+ return (a) -> {
+ if (b == 2)
+ return a * a;
+ else
+ return Math.pow(a, b);
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteBiConsumer.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteBiConsumer.java b/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteBiConsumer.java
new file mode 100644
index 0000000..22e8274
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteBiConsumer.java
@@ -0,0 +1,12 @@
+package org.apache.ignite.math.functions;
+
+import java.io.Serializable;
+import java.util.function.BiConsumer;
+
+/**
+ * Serializable binary consumer.
+ *
+ * @see java.util.function.BiConsumer
+ */
+public interface IgniteBiConsumer<T, U> extends BiConsumer<T, U>, Serializable {
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteBiFunction.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteBiFunction.java b/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteBiFunction.java
new file mode 100644
index 0000000..9d9c147
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteBiFunction.java
@@ -0,0 +1,29 @@
+/*
+ * 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.math.functions;
+
+import java.io.Serializable;
+import java.util.function.BiFunction;
+
+/**
+ * Serializable binary function.
+ *
+ * @see java.util.function.BiFunction
+ */
+public interface IgniteBiFunction<A, B, T> extends BiFunction<A, B, T>, Serializable {
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteConsumer.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteConsumer.java b/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteConsumer.java
new file mode 100644
index 0000000..1f7ca07
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteConsumer.java
@@ -0,0 +1,29 @@
+/*
+ * 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.math.functions;
+
+import java.io.Serializable;
+import java.util.function.Consumer;
+
+/**
+ * Serializable consumer.
+ *
+ * @see java.util.function.Consumer
+ */
+public interface IgniteConsumer<T> extends Consumer<T>, Serializable {
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteDoubleFunction.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteDoubleFunction.java b/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteDoubleFunction.java
new file mode 100644
index 0000000..7a23d50
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteDoubleFunction.java
@@ -0,0 +1,29 @@
+/*
+ * 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.math.functions;
+
+import java.io.Serializable;
+import java.util.function.DoubleFunction;
+
+/**
+ * Serializable double function.
+ *
+ * @see java.util.function.DoubleFunction
+ */
+public interface IgniteDoubleFunction<Double> extends DoubleFunction<Double>, Serializable {
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteFunction.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteFunction.java b/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteFunction.java
new file mode 100644
index 0000000..cfe89a4
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/functions/IgniteFunction.java
@@ -0,0 +1,30 @@
+/*
+ * 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.math.functions;
+
+import java.io.Serializable;
+import java.util.function.Function;
+
+/**
+ * Serializable function.
+ *
+ * @see java.util.function.Function
+ */
+public interface IgniteFunction<T, R> extends Function<T, R>, Serializable {
+
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/functions/IntDoubleToVoidFunction.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/functions/IntDoubleToVoidFunction.java b/modules/ml/src/main/java/org/apache/ignite/math/functions/IntDoubleToVoidFunction.java
new file mode 100644
index 0000000..e5d69c7
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/functions/IntDoubleToVoidFunction.java
@@ -0,0 +1,25 @@
+/*
+ * 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.math.functions;
+
+/**
+ * Setter function for the vector.
+ */
+public interface IntDoubleToVoidFunction extends IgniteBiConsumer<Integer, Double> {
+
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/functions/IntIntDoubleToVoidFunction.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/functions/IntIntDoubleToVoidFunction.java b/modules/ml/src/main/java/org/apache/ignite/math/functions/IntIntDoubleToVoidFunction.java
new file mode 100644
index 0000000..cad8c3c
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/functions/IntIntDoubleToVoidFunction.java
@@ -0,0 +1,28 @@
+/*
+ * 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.math.functions;
+
+import java.io.Serializable;
+
+/**
+ * Setter function for matrices.
+ */
+public interface IntIntDoubleToVoidFunction extends Serializable {
+ /** */
+ public void apply(int x, int y, double v);
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/functions/IntIntToDoubleFunction.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/functions/IntIntToDoubleFunction.java b/modules/ml/src/main/java/org/apache/ignite/math/functions/IntIntToDoubleFunction.java
new file mode 100644
index 0000000..b31d9f9
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/functions/IntIntToDoubleFunction.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.math.functions;
+
+/**
+ * Getters functions for matrices.
+ */
+public interface IntIntToDoubleFunction extends IgniteBiFunction<Integer, Integer, Double> {
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/functions/package-info.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/functions/package-info.java b/modules/ml/src/main/java/org/apache/ignite/math/functions/package-info.java
new file mode 100644
index 0000000..133e62c
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/functions/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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 description. -->
+ * Contains serializable functions for distributed code algebra.
+ */
+package org.apache.ignite.math.functions;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/main/java/org/apache/ignite/math/impls/CacheUtils.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/main/java/org/apache/ignite/math/impls/CacheUtils.java b/modules/ml/src/main/java/org/apache/ignite/math/impls/CacheUtils.java
new file mode 100644
index 0000000..df33895
--- /dev/null
+++ b/modules/ml/src/main/java/org/apache/ignite/math/impls/CacheUtils.java
@@ -0,0 +1,356 @@
+/*
+ * 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.math.impls;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import javax.cache.Cache;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.cache.affinity.Affinity;
+import org.apache.ignite.cache.query.ScanQuery;
+import org.apache.ignite.cluster.ClusterGroup;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.lang.IgniteCallable;
+import org.apache.ignite.lang.IgniteRunnable;
+import org.apache.ignite.math.KeyMapper;
+import org.apache.ignite.math.ValueMapper;
+import org.apache.ignite.math.functions.IgniteBiFunction;
+import org.apache.ignite.math.functions.IgniteConsumer;
+import org.apache.ignite.math.functions.IgniteFunction;
+
+/**
+ * Distribution-related misc. support.
+ */
+public class CacheUtils {
+ /**
+ * Cache entry support.
+ *
+ * @param <K>
+ * @param <V>
+ */
+ public static class CacheEntry<K, V> {
+ /** */
+ private Cache.Entry<K, V> entry;
+ /** */
+ private IgniteCache<K, V> cache;
+
+ /**
+ * @param entry Original cache entry.
+ * @param cache Cache instance.
+ */
+ CacheEntry(Cache.Entry<K, V> entry, IgniteCache<K, V> cache) {
+ this.entry = entry;
+ this.cache = cache;
+ }
+
+ /**
+ *
+ *
+ */
+ public Cache.Entry<K, V> entry() {
+ return entry;
+ }
+
+ /**
+ *
+ *
+ */
+ public IgniteCache<K, V> cache() {
+ return cache;
+ }
+ }
+
+ /**
+ * Gets local Ignite instance.
+ */
+ public static Ignite ignite() {
+ return Ignition.localIgnite();
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @param k Key into the cache.
+ * @param <K> Key type.
+ * @return Cluster group for given key.
+ */
+ public static <K> ClusterGroup groupForKey(String cacheName, K k) {
+ return ignite().cluster().forNode(ignite().affinity(cacheName).mapKeyToNode(k));
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @param keyMapper {@link KeyMapper} to validate cache key.
+ * @param valMapper {@link ValueMapper} to obtain double value for given cache key.
+ * @param <K> Cache key object type.
+ * @param <V> Cache value object type.
+ * @return Sum of the values obtained for valid keys.
+ */
+ public static <K, V> double sum(String cacheName, KeyMapper<K> keyMapper, ValueMapper<V> valMapper) {
+ Collection<Double> subSums = fold(cacheName, (CacheEntry<K, V> ce, Double acc) -> {
+ if (keyMapper.isValid(ce.entry().getKey())) {
+ double v = valMapper.toDouble(ce.entry().getValue());
+
+ return acc == null ? v : acc + v;
+ }
+ else
+ return acc;
+ });
+
+ return sum(subSums);
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @return Sum obtained using sparse logic.
+ */
+ public static <K, V> double sparseSum(String cacheName) {
+ Collection<Double> subSums = fold(cacheName, (CacheEntry<Integer, Map<Integer, Double>> ce, Double acc) -> {
+ Map<Integer, Double> map = ce.entry().getValue();
+
+ double sum = sum(map.values());
+
+ return acc == null ? sum : acc + sum;
+ });
+
+ return sum(subSums);
+ }
+
+ /**
+ * @param c {@link Collection} of double values to sum.
+ * @return Sum of the values.
+ */
+ private static double sum(Collection<Double> c) {
+ double sum = 0.0;
+
+ for (double d : c)
+ sum += d;
+
+ return sum;
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @param keyMapper {@link KeyMapper} to validate cache key.
+ * @param valMapper {@link ValueMapper} to obtain double value for given cache key.
+ * @param <K> Cache key object type.
+ * @param <V> Cache value object type.
+ * @return Minimum value for valid keys.
+ */
+ public static <K, V> double min(String cacheName, KeyMapper<K> keyMapper, ValueMapper<V> valMapper) {
+ Collection<Double> mins = fold(cacheName, (CacheEntry<K, V> ce, Double acc) -> {
+ if (keyMapper.isValid(ce.entry().getKey())) {
+ double v = valMapper.toDouble(ce.entry().getValue());
+
+ if (acc == null)
+ return v;
+ else
+ return Math.min(acc, v);
+ }
+ else
+ return acc;
+ });
+
+ return Collections.min(mins);
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @return Minimum value obtained using sparse logic.
+ */
+ public static <K, V> double sparseMin(String cacheName) {
+ Collection<Double> mins = fold(cacheName, (CacheEntry<Integer, Map<Integer, Double>> ce, Double acc) -> {
+ Map<Integer, Double> map = ce.entry().getValue();
+
+ double min = Collections.min(map.values());
+
+ if (acc == null)
+ return min;
+ else
+ return Math.min(acc, min);
+ });
+
+ return Collections.min(mins);
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @return Maximum value obtained using sparse logic.
+ */
+ public static <K, V> double sparseMax(String cacheName) {
+ Collection<Double> maxes = fold(cacheName, (CacheEntry<Integer, Map<Integer, Double>> ce, Double acc) -> {
+ Map<Integer, Double> map = ce.entry().getValue();
+
+ double max = Collections.max(map.values());
+
+ if (acc == null)
+ return max;
+ else
+ return Math.max(acc, max);
+ });
+
+ return Collections.max(maxes);
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @param keyMapper {@link KeyMapper} to validate cache key.
+ * @param valMapper {@link ValueMapper} to obtain double value for given cache key.
+ * @param <K> Cache key object type.
+ * @param <V> Cache value object type.
+ * @return Maximum value for valid keys.
+ */
+ public static <K, V> double max(String cacheName, KeyMapper<K> keyMapper, ValueMapper<V> valMapper) {
+ Collection<Double> maxes = fold(cacheName, (CacheEntry<K, V> ce, Double acc) -> {
+ if (keyMapper.isValid(ce.entry().getKey())) {
+ double v = valMapper.toDouble(ce.entry().getValue());
+
+ if (acc == null)
+ return v;
+ else
+ return Math.max(acc, v);
+ }
+ else
+ return acc;
+ });
+
+ return Collections.max(maxes);
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @param keyMapper {@link KeyMapper} to validate cache key.
+ * @param valMapper {@link ValueMapper} to obtain double value for given cache key.
+ * @param mapper Mapping {@link IgniteFunction}.
+ * @param <K> Cache key object type.
+ * @param <V> Cache value object type.
+ */
+ public static <K, V> void map(String cacheName, KeyMapper<K> keyMapper, ValueMapper<V> valMapper,
+ IgniteFunction<Double, Double> mapper) {
+ foreach(cacheName, (CacheEntry<K, V> ce) -> {
+ K k = ce.entry().getKey();
+
+ if (keyMapper.isValid(k))
+ // Actual assignment.
+ ce.cache().put(k, valMapper.fromDouble(mapper.apply(valMapper.toDouble(ce.entry().getValue()))));
+ });
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @param mapper Mapping {@link IgniteFunction}.
+ */
+ public static <K, V> void sparseMap(String cacheName, IgniteFunction<Double, Double> mapper) {
+ foreach(cacheName, (CacheEntry<Integer, Map<Integer, Double>> ce) -> {
+ Integer k = ce.entry().getKey();
+ Map<Integer, Double> v = ce.entry().getValue();
+
+ for (Map.Entry<Integer, Double> e : v.entrySet())
+ e.setValue(mapper.apply(e.getValue()));
+
+ ce.cache().put(k, v);
+ });
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @param fun An operation that accepts a cache entry and processes it.
+ * @param <K> Cache key object type.
+ * @param <V> Cache value object type.
+ */
+ public static <K, V> void foreach(String cacheName, IgniteConsumer<CacheEntry<K, V>> fun) {
+ bcast(cacheName, () -> {
+ Ignite ignite = Ignition.localIgnite();
+ IgniteCache<K, V> cache = ignite.getOrCreateCache(cacheName);
+
+ int partsCnt = ignite.affinity(cacheName).partitions();
+
+ // Use affinity in filter for scan query. Otherwise we accept consumer in each node which is wrong.
+ Affinity affinity = ignite.affinity(cacheName);
+ ClusterNode locNode = ignite.cluster().localNode();
+
+ // Iterate over all partitions. Some of them will be stored on that local node.
+ for (int part = 0; part < partsCnt; part++) {
+ int p = part;
+
+ // Iterate over given partition.
+ // Query returns an empty cursor if this partition is not stored on this node.
+ for (Cache.Entry<K, V> entry : cache.query(new ScanQuery<K, V>(part,
+ (k, v) -> affinity.mapPartitionToNode(p) == locNode)))
+ fun.accept(new CacheEntry<>(entry, cache));
+ }
+ });
+ }
+
+ /**
+ * <b>Currently fold supports only commutative operations.<b/>
+ *
+ * @param cacheName Cache name.
+ * @param folder Fold function operating over cache entries.
+ * @param <K> Cache key object type.
+ * @param <V> Cache value object type.
+ * @param <A> Fold result type.
+ * @return Fold operation result.
+ */
+ public static <K, V, A> Collection<A> fold(String cacheName, IgniteBiFunction<CacheEntry<K, V>, A, A> folder) {
+ return bcast(cacheName, () -> {
+ Ignite ignite = Ignition.localIgnite();
+ IgniteCache<K, V> cache = ignite.getOrCreateCache(cacheName);
+
+ int partsCnt = ignite.affinity(cacheName).partitions();
+
+ // Use affinity in filter for ScanQuery. Otherwise we accept consumer in each node which is wrong.
+ Affinity affinity = ignite.affinity(cacheName);
+ ClusterNode locNode = ignite.cluster().localNode();
+
+ A a = null;
+
+ // Iterate over all partitions. Some of them will be stored on that local node.
+ for (int part = 0; part < partsCnt; part++) {
+ int p = part;
+
+ // Iterate over given partition.
+ // Query returns an empty cursor if this partition is not stored on this node.
+ for (Cache.Entry<K, V> entry : cache.query(new ScanQuery<K, V>(part,
+ (k, v) -> affinity.mapPartitionToNode(p) == locNode)))
+ a = folder.apply(new CacheEntry<>(entry, cache), a);
+ }
+
+ return a;
+ });
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @param run {@link Runnable} to broadcast to cache nodes for given cache name.
+ */
+ public static void bcast(String cacheName, IgniteRunnable run) {
+ ignite().compute(ignite().cluster().forCacheNodes(cacheName)).broadcast(run);
+ }
+
+ /**
+ * @param cacheName Cache name.
+ * @param call {@link IgniteCallable} to broadcast to cache nodes for given cache name.
+ * @param <A> Type returned by the callable.
+ */
+ public static <A> Collection<A> bcast(String cacheName, IgniteCallable<A> call) {
+ return ignite().compute(ignite().cluster().forCacheNodes(cacheName)).broadcast(call);
+ }
+}