blob: a1fad5f59e88691e6dfd5a2ab5f269599c36c13c [file] [log] [blame]
/*
* 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.commons.math3.linear;
import org.junit.Test;
import org.junit.Assert;
import org.apache.commons.math3.TestUtils;
import org.apache.commons.math3.fraction.Fraction;
import org.apache.commons.math3.fraction.FractionField;
public class FieldLUDecompositionTest {
private Fraction[][] testData = {
{ new Fraction(1), new Fraction(2), new Fraction(3)},
{ new Fraction(2), new Fraction(5), new Fraction(3)},
{ new Fraction(1), new Fraction(0), new Fraction(8)}
};
private Fraction[][] testDataMinus = {
{ new Fraction(-1), new Fraction(-2), new Fraction(-3)},
{ new Fraction(-2), new Fraction(-5), new Fraction(-3)},
{ new Fraction(-1), new Fraction(0), new Fraction(-8)}
};
private Fraction[][] luData = {
{ new Fraction(2), new Fraction(3), new Fraction(3) },
{ new Fraction(2), new Fraction(3), new Fraction(7) },
{ new Fraction(6), new Fraction(6), new Fraction(8) }
};
// singular matrices
private Fraction[][] singular = {
{ new Fraction(2), new Fraction(3) },
{ new Fraction(2), new Fraction(3) }
};
private Fraction[][] bigSingular = {
{ new Fraction(1), new Fraction(2), new Fraction(3), new Fraction(4) },
{ new Fraction(2), new Fraction(5), new Fraction(3), new Fraction(4) },
{ new Fraction(7), new Fraction(3), new Fraction(256), new Fraction(1930) },
{ new Fraction(3), new Fraction(7), new Fraction(6), new Fraction(8) }
}; // 4th row = 1st + 2nd
/** test dimensions */
@Test
public void testDimensions() {
FieldMatrix<Fraction> matrix =
new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), testData);
FieldLUDecomposition<Fraction> LU = new FieldLUDecomposition<Fraction>(matrix);
Assert.assertEquals(testData.length, LU.getL().getRowDimension());
Assert.assertEquals(testData.length, LU.getL().getColumnDimension());
Assert.assertEquals(testData.length, LU.getU().getRowDimension());
Assert.assertEquals(testData.length, LU.getU().getColumnDimension());
Assert.assertEquals(testData.length, LU.getP().getRowDimension());
Assert.assertEquals(testData.length, LU.getP().getColumnDimension());
}
/** test non-square matrix */
@Test
public void testNonSquare() {
try {
// we don't use FractionField.getInstance() for testing purposes
new FieldLUDecomposition<Fraction>(new Array2DRowFieldMatrix<Fraction>(new Fraction[][] {
{ Fraction.ZERO, Fraction.ZERO },
{ Fraction.ZERO, Fraction.ZERO },
{ Fraction.ZERO, Fraction.ZERO }
}));
Assert.fail("Expected NonSquareMatrixException");
} catch (NonSquareMatrixException ime) {
// expected behavior
}
}
/** test PA = LU */
@Test
public void testPAEqualLU() {
FieldMatrix<Fraction> matrix = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), testData);
FieldLUDecomposition<Fraction> lu = new FieldLUDecomposition<Fraction>(matrix);
FieldMatrix<Fraction> l = lu.getL();
FieldMatrix<Fraction> u = lu.getU();
FieldMatrix<Fraction> p = lu.getP();
TestUtils.assertEquals(p.multiply(matrix), l.multiply(u));
matrix = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), testDataMinus);
lu = new FieldLUDecomposition<Fraction>(matrix);
l = lu.getL();
u = lu.getU();
p = lu.getP();
TestUtils.assertEquals(p.multiply(matrix), l.multiply(u));
matrix = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), 17, 17);
for (int i = 0; i < matrix.getRowDimension(); ++i) {
matrix.setEntry(i, i, Fraction.ONE);
}
lu = new FieldLUDecomposition<Fraction>(matrix);
l = lu.getL();
u = lu.getU();
p = lu.getP();
TestUtils.assertEquals(p.multiply(matrix), l.multiply(u));
matrix = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), singular);
lu = new FieldLUDecomposition<Fraction>(matrix);
Assert.assertFalse(lu.getSolver().isNonSingular());
Assert.assertNull(lu.getL());
Assert.assertNull(lu.getU());
Assert.assertNull(lu.getP());
matrix = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), bigSingular);
lu = new FieldLUDecomposition<Fraction>(matrix);
Assert.assertFalse(lu.getSolver().isNonSingular());
Assert.assertNull(lu.getL());
Assert.assertNull(lu.getU());
Assert.assertNull(lu.getP());
}
/** test that L is lower triangular with unit diagonal */
@Test
public void testLLowerTriangular() {
FieldMatrix<Fraction> matrix = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), testData);
FieldMatrix<Fraction> l = new FieldLUDecomposition<Fraction>(matrix).getL();
for (int i = 0; i < l.getRowDimension(); i++) {
Assert.assertEquals(Fraction.ONE, l.getEntry(i, i));
for (int j = i + 1; j < l.getColumnDimension(); j++) {
Assert.assertEquals(Fraction.ZERO, l.getEntry(i, j));
}
}
}
/** test that U is upper triangular */
@Test
public void testUUpperTriangular() {
FieldMatrix<Fraction> matrix = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), testData);
FieldMatrix<Fraction> u = new FieldLUDecomposition<Fraction>(matrix).getU();
for (int i = 0; i < u.getRowDimension(); i++) {
for (int j = 0; j < i; j++) {
Assert.assertEquals(Fraction.ZERO, u.getEntry(i, j));
}
}
}
/** test that P is a permutation matrix */
@Test
public void testPPermutation() {
FieldMatrix<Fraction> matrix = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), testData);
FieldMatrix<Fraction> p = new FieldLUDecomposition<Fraction>(matrix).getP();
FieldMatrix<Fraction> ppT = p.multiply(p.transpose());
FieldMatrix<Fraction> id =
new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(),
p.getRowDimension(), p.getRowDimension());
for (int i = 0; i < id.getRowDimension(); ++i) {
id.setEntry(i, i, Fraction.ONE);
}
TestUtils.assertEquals(id, ppT);
for (int i = 0; i < p.getRowDimension(); i++) {
int zeroCount = 0;
int oneCount = 0;
int otherCount = 0;
for (int j = 0; j < p.getColumnDimension(); j++) {
final Fraction e = p.getEntry(i, j);
if (e.equals(Fraction.ZERO)) {
++zeroCount;
} else if (e.equals(Fraction.ONE)) {
++oneCount;
} else {
++otherCount;
}
}
Assert.assertEquals(p.getColumnDimension() - 1, zeroCount);
Assert.assertEquals(1, oneCount);
Assert.assertEquals(0, otherCount);
}
for (int j = 0; j < p.getColumnDimension(); j++) {
int zeroCount = 0;
int oneCount = 0;
int otherCount = 0;
for (int i = 0; i < p.getRowDimension(); i++) {
final Fraction e = p.getEntry(i, j);
if (e.equals(Fraction.ZERO)) {
++zeroCount;
} else if (e.equals(Fraction.ONE)) {
++oneCount;
} else {
++otherCount;
}
}
Assert.assertEquals(p.getRowDimension() - 1, zeroCount);
Assert.assertEquals(1, oneCount);
Assert.assertEquals(0, otherCount);
}
}
/** test singular */
@Test
public void testSingular() {
FieldLUDecomposition<Fraction> lu =
new FieldLUDecomposition<Fraction>(new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), testData));
Assert.assertTrue(lu.getSolver().isNonSingular());
lu = new FieldLUDecomposition<Fraction>(new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), singular));
Assert.assertFalse(lu.getSolver().isNonSingular());
lu = new FieldLUDecomposition<Fraction>(new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), bigSingular));
Assert.assertFalse(lu.getSolver().isNonSingular());
}
/** test matrices values */
@Test
public void testMatricesValues1() {
FieldLUDecomposition<Fraction> lu =
new FieldLUDecomposition<Fraction>(new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), testData));
FieldMatrix<Fraction> lRef = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), new Fraction[][] {
{ new Fraction(1), new Fraction(0), new Fraction(0) },
{ new Fraction(2), new Fraction(1), new Fraction(0) },
{ new Fraction(1), new Fraction(-2), new Fraction(1) }
});
FieldMatrix<Fraction> uRef = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), new Fraction[][] {
{ new Fraction(1), new Fraction(2), new Fraction(3) },
{ new Fraction(0), new Fraction(1), new Fraction(-3) },
{ new Fraction(0), new Fraction(0), new Fraction(-1) }
});
FieldMatrix<Fraction> pRef = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), new Fraction[][] {
{ new Fraction(1), new Fraction(0), new Fraction(0) },
{ new Fraction(0), new Fraction(1), new Fraction(0) },
{ new Fraction(0), new Fraction(0), new Fraction(1) }
});
int[] pivotRef = { 0, 1, 2 };
// check values against known references
FieldMatrix<Fraction> l = lu.getL();
TestUtils.assertEquals(lRef, l);
FieldMatrix<Fraction> u = lu.getU();
TestUtils.assertEquals(uRef, u);
FieldMatrix<Fraction> p = lu.getP();
TestUtils.assertEquals(pRef, p);
int[] pivot = lu.getPivot();
for (int i = 0; i < pivotRef.length; ++i) {
Assert.assertEquals(pivotRef[i], pivot[i]);
}
// check the same cached instance is returned the second time
Assert.assertTrue(l == lu.getL());
Assert.assertTrue(u == lu.getU());
Assert.assertTrue(p == lu.getP());
}
/** test matrices values */
@Test
public void testMatricesValues2() {
FieldLUDecomposition<Fraction> lu =
new FieldLUDecomposition<Fraction>(new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), luData));
FieldMatrix<Fraction> lRef = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), new Fraction[][] {
{ new Fraction(1), new Fraction(0), new Fraction(0) },
{ new Fraction(3), new Fraction(1), new Fraction(0) },
{ new Fraction(1), new Fraction(0), new Fraction(1) }
});
FieldMatrix<Fraction> uRef = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), new Fraction[][] {
{ new Fraction(2), new Fraction(3), new Fraction(3) },
{ new Fraction(0), new Fraction(-3), new Fraction(-1) },
{ new Fraction(0), new Fraction(0), new Fraction(4) }
});
FieldMatrix<Fraction> pRef = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), new Fraction[][] {
{ new Fraction(1), new Fraction(0), new Fraction(0) },
{ new Fraction(0), new Fraction(0), new Fraction(1) },
{ new Fraction(0), new Fraction(1), new Fraction(0) }
});
int[] pivotRef = { 0, 2, 1 };
// check values against known references
FieldMatrix<Fraction> l = lu.getL();
TestUtils.assertEquals(lRef, l);
FieldMatrix<Fraction> u = lu.getU();
TestUtils.assertEquals(uRef, u);
FieldMatrix<Fraction> p = lu.getP();
TestUtils.assertEquals(pRef, p);
int[] pivot = lu.getPivot();
for (int i = 0; i < pivotRef.length; ++i) {
Assert.assertEquals(pivotRef[i], pivot[i]);
}
// check the same cached instance is returned the second time
Assert.assertTrue(l == lu.getL());
Assert.assertTrue(u == lu.getU());
Assert.assertTrue(p == lu.getP());
}
}