Author: mikl Date: Mon Mar 21 09:28:34 2011 New Revision: 1083713 URL: http://svn.apache.org/viewvc?rev=1083713&view=rev Log: Fixes MATH-435 for FieldMatrix<T>, too.
Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractFieldMatrix.java commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/FieldMatrix.java commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/FieldMatrixImplTest.java Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractFieldMatrix.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractFieldMatrix.java?rev=1083713&r1=1083712&r2=1083713&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractFieldMatrix.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/AbstractFieldMatrix.java Mon Mar 21 09:28:34 2011 @@ -18,6 +18,7 @@ package org.apache.commons.math.linear; import java.lang.reflect.Array; +import java.util.ArrayList; import java.util.Arrays; import org.apache.commons.math.Field; @@ -264,6 +265,65 @@ public abstract class AbstractFieldMatri public FieldMatrix<T> preMultiply(final FieldMatrix<T> m) { return m.multiply(this); } + + /** {@inheritDoc} */ + @Override + public FieldMatrix<T> power(final int p) { + if (p < 0) { + throw new IllegalArgumentException("p must be >= 0"); + } + + if (!isSquare()) { + throw new NonSquareMatrixException(getRowDimension(), getColumnDimension()); + } + + if (p == 0) { + return MatrixUtils.createFieldIdentityMatrix(this.getField(), this.getRowDimension()); + } + + if (p == 1) { + return this.copy(); + } + + final int power = p - 1; + + /* + * Only log_2(p) operations is used by doing as follows: + * 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2 + * + * In general, the same approach is used for A^p. + */ + + final char[] binaryRepresentation = Integer.toBinaryString(power) + .toCharArray(); + final ArrayList<Integer> nonZeroPositions = new ArrayList<Integer>(); + + for (int i = 0; i < binaryRepresentation.length; ++i) { + if (binaryRepresentation[i] == '1') { + final int pos = binaryRepresentation.length - i - 1; + nonZeroPositions.add(pos); + } + } + + ArrayList<FieldMatrix<T>> results = new ArrayList<FieldMatrix<T>>( + binaryRepresentation.length); + + results.add(0, this.copy()); + + for (int i = 1; i < binaryRepresentation.length; ++i) { + final FieldMatrix<T> s = results.get(i - 1); + final FieldMatrix<T> r = s.multiply(s); + results.add(i, r); + } + + FieldMatrix<T> result = this.copy(); + + for (Integer i : nonZeroPositions) { + result = result.multiply(results.get(i)); + } + + return result; + } /** {@inheritDoc} */ public T[][] getData() { Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/FieldMatrix.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/FieldMatrix.java?rev=1083713&r1=1083712&r2=1083713&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/FieldMatrix.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/FieldMatrix.java Mon Mar 21 09:28:34 2011 @@ -116,6 +116,17 @@ public interface FieldMatrix<T extends F FieldMatrix<T> preMultiply(FieldMatrix<T> m); /** + * Returns the result multiplying this with itself <code>p</code> times. + * Depending on the type of the field elements, T, + * instability for high powers might occur. + * @param p raise this to power p + * @return this^p + * @throws IllegalArgumentException if p < 0 + * NonSquareMatrixException if the matrix is not square + */ + FieldMatrix<T> power(final int p); + + /** * Returns matrix entries as a two-dimensional array. * * @return a 2-dimensional array of entries. Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/FieldMatrixImplTest.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/FieldMatrixImplTest.java?rev=1083713&r1=1083712&r2=1083713&view=diff ============================================================================== --- commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/FieldMatrixImplTest.java (original) +++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/FieldMatrixImplTest.java Mon Mar 21 09:28:34 2011 @@ -199,6 +199,52 @@ public final class FieldMatrixImplTest { TestUtils.assertEquals(m3.multiply(m4), m5); } + @Test + public void testPower() { + FieldMatrix<Fraction> m = new Array2DRowFieldMatrix<Fraction>(testData); + FieldMatrix<Fraction> mInv = new Array2DRowFieldMatrix<Fraction>(testDataInv); + FieldMatrix<Fraction> mPlusInv = new Array2DRowFieldMatrix<Fraction>(testDataPlusInv); + FieldMatrix<Fraction> identity = new Array2DRowFieldMatrix<Fraction>(id); + + TestUtils.assertEquals(m.power(0), identity); + TestUtils.assertEquals(mInv.power(0), identity); + TestUtils.assertEquals(mPlusInv.power(0), identity); + + TestUtils.assertEquals(m.power(1), m); + TestUtils.assertEquals(mInv.power(1), mInv); + TestUtils.assertEquals(mPlusInv.power(1), mPlusInv); + + FieldMatrix<Fraction> C1 = m.copy(); + FieldMatrix<Fraction> C2 = mInv.copy(); + FieldMatrix<Fraction> C3 = mPlusInv.copy(); + + // stop at 5 to avoid overflow + for (int i = 2; i <= 5; ++i) { + C1 = C1.multiply(m); + C2 = C2.multiply(mInv); + C3 = C3.multiply(mPlusInv); + + TestUtils.assertEquals(m.power(i), C1); + TestUtils.assertEquals(mInv.power(i), C2); + TestUtils.assertEquals(mPlusInv.power(i), C3); + } + + try { + FieldMatrix<Fraction> mNotSquare = new Array2DRowFieldMatrix<Fraction>(testData2T); + mNotSquare.power(2); + Assert.fail("Expecting NonSquareMatrixException"); + } catch (NonSquareMatrixException ex) { + // ignored + } + + try { + m.power(-1); + Assert.fail("Expecting IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // ignored + } + } + /** test trace */ @Test public void testTrace() {