/*
* 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.Vector;
import org.apache.ignite.ml.math.exceptions.CardinalityException;
import org.apache.ignite.ml.math.exceptions.SingularMatrixException;
import org.apache.ignite.ml.math.impls.matrix.DenseLocalOnHeapMatrix;
import org.apache.ignite.ml.math.impls.matrix.PivotedMatrixView;
import org.apache.ignite.ml.math.impls.vector.DenseLocalOnHeapVector;
import org.apache.ignite.ml.math.util.MatrixUtil;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Tests for {@link LUDecomposition}.
*/
public class LUDecompositionTest {
/** */
private Matrix testL;
/** */
private Matrix testU;
/** */
private Matrix testP;
/** */
private Matrix testMatrix;
/** */
private int[] rawPivot;
/** */
@Before
public void setUp() {
double[][] rawMatrix = new double[][] {
{2.0d, 1.0d, 1.0d, 0.0d},
{4.0d, 3.0d, 3.0d, 1.0d},
{8.0d, 7.0d, 9.0d, 5.0d},
{6.0d, 7.0d, 9.0d, 8.0d}};
double[][] rawL = {
{1.0d, 0.0d, 0.0d, 0.0d},
{3.0d / 4.0d, 1.0d, 0.0d, 0.0d},
{1.0d / 2.0d, -2.0d / 7.0d, 1.0d, 0.0d},
{1.0d / 4.0d, -3.0d / 7.0d, 1.0d / 3.0d, 1.0d}};
double[][] rawU = {
{8.0d, 7.0d, 9.0d, 5.0d},
{0.0d, 7.0d / 4.0d, 9.0d / 4.0d, 17.0d / 4.0d},
{0.0d, 0.0d, -6.0d / 7.0d, -2.0d / 7.0d},
{0.0d, 0.0d, 0.0d, 2.0d / 3.0d}};
double[][] rawP = new double[][] {
{0, 0, 1.0d, 0},
{0, 0, 0, 1.0d},
{0, 1.0d, 0, 0},
{1.0d, 0, 0, 0}};
rawPivot = new int[] {3, 4, 2, 1};
testMatrix = new DenseLocalOnHeapMatrix(rawMatrix);
testL = new DenseLocalOnHeapMatrix(rawL);
testU = new DenseLocalOnHeapMatrix(rawU);
testP = new DenseLocalOnHeapMatrix(rawP);
}
/** */
@Test
public void getL() throws Exception {
Matrix luDecompositionL = new LUDecomposition(testMatrix).getL();
assertEquals("Unexpected row size.", testL.rowSize(), luDecompositionL.rowSize());
assertEquals("Unexpected column size.", testL.columnSize(), luDecompositionL.columnSize());
for (int i = 0; i < testL.rowSize(); i++)
for (int j = 0; j < testL.columnSize(); j++)
assertEquals("Unexpected value at (" + i + "," + j + ").",
testL.getX(i, j), luDecompositionL.getX(i, j), 0.0000001d);
luDecompositionL.destroy();
}
/** */
@Test
public void getU() throws Exception {
Matrix luDecompositionU = new LUDecomposition(testMatrix).getU();
assertEquals("Unexpected row size.", testU.rowSize(), luDecompositionU.rowSize());
assertEquals("Unexpected column size.", testU.columnSize(), luDecompositionU.columnSize());
for (int i = 0; i < testU.rowSize(); i++)
for (int j = 0; j < testU.columnSize(); j++)
assertEquals("Unexpected value at (" + i + "," + j + ").",
testU.getX(i, j), luDecompositionU.getX(i, j), 0.0000001d);
luDecompositionU.destroy();
}
/** */
@Test
public void getP() throws Exception {
Matrix luDecompositionP = new LUDecomposition(testMatrix).getP();
assertEquals("Unexpected row size.", testP.rowSize(), luDecompositionP.rowSize());
assertEquals("Unexpected column size.", testP.columnSize(), luDecompositionP.columnSize());
for (int i = 0; i < testP.rowSize(); i++)
for (int j = 0; j < testP.columnSize(); j++)
assertEquals("Unexpected value at (" + i + "," + j + ").",
testP.getX(i, j), luDecompositionP.getX(i, j), 0.0000001d);
luDecompositionP.destroy();
}
/** */
@Test
public void getPivot() throws Exception {
Vector pivot = new LUDecomposition(testMatrix).getPivot();
assertEquals("Unexpected pivot size.", rawPivot.length, pivot.size());
for (int i = 0; i < testU.rowSize(); i++)
assertEquals("Unexpected value at " + i, rawPivot[i], (int)pivot.get(i) + 1);
}
/**
* Test for {@link MatrixUtil} features (more specifically, we test matrix which does not have
* a native like/copy methods support).
*/
@Test
public void matrixUtilTest() {
LUDecomposition dec = new LUDecomposition(new PivotedMatrixView(testMatrix));
Matrix luDecompositionL = dec.getL();
assertEquals("Unexpected L row size.", testL.rowSize(), luDecompositionL.rowSize());
assertEquals("Unexpected L column size.", testL.columnSize(), luDecompositionL.columnSize());
for (int i = 0; i < testL.rowSize(); i++)
for (int j = 0; j < testL.columnSize(); j++)
assertEquals("Unexpected L value at (" + i + "," + j + ").",
testL.getX(i, j), luDecompositionL.getX(i, j), 0.0000001d);
Matrix luDecompositionU = dec.getU();
assertEquals("Unexpected U row size.", testU.rowSize(), luDecompositionU.rowSize());
assertEquals("Unexpected U column size.", testU.columnSize(), luDecompositionU.columnSize());
for (int i = 0; i < testU.rowSize(); i++)
for (int j = 0; j < testU.columnSize(); j++)
assertEquals("Unexpected U value at (" + i + "," + j + ").",
testU.getX(i, j), luDecompositionU.getX(i, j), 0.0000001d);
Matrix luDecompositionP = dec.getP();
assertEquals("Unexpected P row size.", testP.rowSize(), luDecompositionP.rowSize());
assertEquals("Unexpected P column size.", testP.columnSize(), luDecompositionP.columnSize());
for (int i = 0; i < testP.rowSize(); i++)
for (int j = 0; j < testP.columnSize(); j++)
assertEquals("Unexpected P value at (" + i + "," + j + ").",
testP.getX(i, j), luDecompositionP.getX(i, j), 0.0000001d);
dec.destroy();
}
/** */
@Test
public void singularDeterminant() throws Exception {
assertEquals("Unexpected determinant for singular matrix decomposition.",
0d, new LUDecomposition(new DenseLocalOnHeapMatrix(2, 2)).determinant(), 0d);
}
/** */
@Test(expected = CardinalityException.class)
public void solveVecWrongSize() throws Exception {
new LUDecomposition(testMatrix).solve(new DenseLocalOnHeapVector(testMatrix.rowSize() + 1));
}
/** */
@Test(expected = SingularMatrixException.class)
public void solveVecSingularMatrix() throws Exception {
new LUDecomposition(new DenseLocalOnHeapMatrix(testMatrix.rowSize(), testMatrix.rowSize()))
.solve(new DenseLocalOnHeapVector(testMatrix.rowSize()));
}
/** */
@Test
public void solveVec() throws Exception {
Vector sol = new LUDecomposition(new PivotedMatrixView(testMatrix))
.solve(new DenseLocalOnHeapVector(testMatrix.rowSize()));
assertEquals("Wrong solution vector size.", testMatrix.rowSize(), sol.size());
for (int i = 0; i < sol.size(); i++)
assertEquals("Unexpected value at index " + i, 0d, sol.getX(i), 0.0000001d);
}
/** */
@Test(expected = CardinalityException.class)
public void solveMtxWrongSize() throws Exception {
new LUDecomposition(testMatrix).solve(
new DenseLocalOnHeapMatrix(testMatrix.rowSize() + 1, testMatrix.rowSize()));
}
/** */
@Test(expected = SingularMatrixException.class)
public void solveMtxSingularMatrix() throws Exception {
new LUDecomposition(new DenseLocalOnHeapMatrix(testMatrix.rowSize(), testMatrix.rowSize()))
.solve(new DenseLocalOnHeapMatrix(testMatrix.rowSize(), testMatrix.rowSize()));
}
/** */
@Test
public void solveMtx() throws Exception {
Matrix sol = new LUDecomposition(new PivotedMatrixView(testMatrix))
.solve(new DenseLocalOnHeapMatrix(testMatrix.rowSize(), testMatrix.rowSize()));
assertEquals("Wrong solution matrix row size.", testMatrix.rowSize(), sol.rowSize());
assertEquals("Wrong solution matrix column size.", testMatrix.rowSize(), sol.columnSize());
for (int row = 0; row < sol.rowSize(); row++)
for (int col = 0; col < sol.columnSize(); col++)
assertEquals("Unexpected P value at (" + row + "," + col + ").",
0d, sol.getX(row, col), 0.0000001d);
}
/** */
@Test(expected = AssertionError.class)
public void nullMatrixTest() {
new LUDecomposition(null);
}
/** */
@Test(expected = CardinalityException.class)
public void nonSquareMatrixTest() {
new LUDecomposition(new DenseLocalOnHeapMatrix(2, 3));
}
}