/*
* 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.decompositions;
import org.apache.ignite.ml.math.Matrix;
import org.apache.ignite.ml.math.impls.matrix.DenseLocalOnHeapMatrix;
import org.apache.ignite.ml.math.impls.matrix.PivotedMatrixView;
import org.apache.ignite.ml.math.util.MatrixUtil;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/** */
public class QRDecompositionTest {
/** */
@Test
public void basicTest() {
basicTest(new DenseLocalOnHeapMatrix(new double[][] {
{2.0d, -1.0d, 0.0d},
{-1.0d, 2.0d, -1.0d},
{0.0d, -1.0d, 2.0d}
}));
}
/**
* Test for {@link MatrixUtil} features (more specifically, we test matrix which does not have
* a native like/copy methods support).
*/
@Test
public void matrixUtilTest() {
basicTest(new PivotedMatrixView(new DenseLocalOnHeapMatrix(new double[][] {
{2.0d, -1.0d, 0.0d},
{-1.0d, 2.0d, -1.0d},
{0.0d, -1.0d, 2.0d}
})));
}
/** */
@Test(expected = AssertionError.class)
public void nullMatrixTest() {
new QRDecomposition(null);
}
/** */
@Test(expected = IllegalArgumentException.class)
public void solveWrongMatrixSizeTest() {
new QRDecomposition(new DenseLocalOnHeapMatrix(new double[][] {
{2.0d, -1.0d, 0.0d},
{-1.0d, 2.0d, -1.0d},
{0.0d, -1.0d, 2.0d}
})).solve(new DenseLocalOnHeapMatrix(2, 3));
}
/** */
private void basicTest(Matrix m) {
QRDecomposition dec = new QRDecomposition(m);
assertTrue("Unexpected value for full rank in decomposition " + dec, dec.hasFullRank());
Matrix q = dec.getQ();
Matrix r = dec.getR();
assertNotNull("Matrix q is expected to be not null.", q);
assertNotNull("Matrix r is expected to be not null.", r);
Matrix qSafeCp = safeCopy(q);
Matrix expIdentity = qSafeCp.times(qSafeCp.transpose());
final double delta = 0.0001;
for (int row = 0; row < expIdentity.rowSize(); row++)
for (int col = 0; col < expIdentity.columnSize(); col++)
assertEquals("Unexpected identity matrix value at (" + row + "," + col + ").",
row == col ? 1d : 0d, expIdentity.get(col, row), delta);
for (int row = 0; row < r.rowSize(); row++)
for (int col = 0; col < row - 1; col++)
assertEquals("Unexpected upper triangular matrix value at (" + row + "," + col + ").",
0d, r.get(row, col), delta);
Matrix recomposed = qSafeCp.times(r);
for (int row = 0; row < m.rowSize(); row++)
for (int col = 0; col < m.columnSize(); col++)
assertEquals("Unexpected recomposed matrix value at (" + row + "," + col + ").",
m.get(row, col), recomposed.get(row, col), delta);
Matrix sol = dec.solve(new DenseLocalOnHeapMatrix(3, 10));
assertEquals("Unexpected rows in solution matrix.", 3, sol.rowSize());
assertEquals("Unexpected cols in solution matrix.", 10, sol.columnSize());
for (int row = 0; row < sol.rowSize(); row++)
for (int col = 0; col < sol.columnSize(); col++)
assertEquals("Unexpected solution matrix value at (" + row + "," + col + ").",
0d, sol.get(row, col), delta);
dec.destroy();
QRDecomposition dec1 = new QRDecomposition(new DenseLocalOnHeapMatrix(new double[][] {
{2.0d, -1.0d},
{-1.0d, 2.0d},
{0.0d, -1.0d}
}));
assertTrue("Unexpected value for full rank in decomposition " + dec1, dec1.hasFullRank());
dec1.destroy();
QRDecomposition dec2 = new QRDecomposition(new DenseLocalOnHeapMatrix(new double[][] {
{2.0d, -1.0d, 0.0d, 0.0d},
{-1.0d, 2.0d, -1.0d, 0.0d},
{0.0d, -1.0d, 2.0d, 0.0d}
}));
assertTrue("Unexpected value for full rank in decomposition " + dec2, dec2.hasFullRank());
dec2.destroy();
}
/** */
private Matrix safeCopy(Matrix orig) {
return new DenseLocalOnHeapMatrix(orig.rowSize(), orig.columnSize()).assign(orig);
}
}