From f6da77e2bccfa107f4ebc87163ec9e6f491c0fd1 Mon Sep 17 00:00:00 2001 From: Phil Steitz Date: Sun, 29 May 2005 20:26:11 +0000 Subject: [PATCH] Added setSubMatrix methods to RealMatrix, BigMatrix. Modified copyIn methods to use setSubMatrix and moved array argument checking from constructors and copyIn to setSubMatrix. PR # 35007 Base implementation contributed by Rodrigo di Lorenzo Lopes git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/math/trunk@178982 13f79535-47bb-0310-9956-ffa450edef68 --- project.xml | 3 + .../apache/commons/math/linear/BigMatrix.java | 28 +++++ .../commons/math/linear/BigMatrixImpl.java | 94 ++++++++++++---- .../commons/math/linear/RealMatrix.java | 32 +++++- .../commons/math/linear/RealMatrixImpl.java | 104 +++++++++++++----- .../math/linear/BigMatrixImplTest.java | 71 +++++++++++- .../math/linear/RealMatrixImplTest.java | 61 +++++++++- xdocs/changes.xml | 3 + 8 files changed, 339 insertions(+), 57 deletions(-) diff --git a/project.xml b/project.xml index 0d0bc5e14..52cc4f5bf 100644 --- a/project.xml +++ b/project.xml @@ -120,6 +120,9 @@ C. Scott Ananian + + Rodrigo di Lorenzo Lopes + Ken Geis diff --git a/src/java/org/apache/commons/math/linear/BigMatrix.java b/src/java/org/apache/commons/math/linear/BigMatrix.java index 031b8efb1..33d7ec623 100644 --- a/src/java/org/apache/commons/math/linear/BigMatrix.java +++ b/src/java/org/apache/commons/math/linear/BigMatrix.java @@ -145,6 +145,34 @@ public interface BigMatrix { BigMatrix getSubMatrix(int[] selectedRows, int[] selectedColumns) throws MatrixIndexException; + /** + * Replace the submatrix starting at row, column using data in + * the input subMatrix array. Indexes are 0-based. + *

+ * Example:
+ * Starting with

+     * 1  2  3  4
+     * 5  6  7  8
+     * 9  0  1  2
+     * 
+ * and subMatrix = {{3, 4} {5,6}}, invoking + * setSubMatrix(subMatrix,1,1)) will result in
+     * 1  2  3  4
+     * 5  3  4  8
+     * 9  5  6  2
+     * 
+ * + * @param subMatrix array containing the submatrix replacement data + * @param row row coordinate of the top, left element to be replaced + * @param column column coordinate of the top, left element to be replaced + * @throws MatrixIndexException if subMatrix does not fit into this + * matrix from element in (row, column) + * @throws IllegalArgumentException if subMatrix is not rectangular + * (not all rows have the same length) or empty + * @throws NullPointerException if subMatrix is null + */ + public void setSubMatrix(BigDecimal subMatrix[][], int row, int column) throws MatrixIndexException; + /** * Returns the entries in row number row * as a row matrix. Row indices start at 0. diff --git a/src/java/org/apache/commons/math/linear/BigMatrixImpl.java b/src/java/org/apache/commons/math/linear/BigMatrixImpl.java index a1302df12..afcf3d53c 100644 --- a/src/java/org/apache/commons/math/linear/BigMatrixImpl.java +++ b/src/java/org/apache/commons/math/linear/BigMatrixImpl.java @@ -113,22 +113,6 @@ public class BigMatrixImpl implements BigMatrix, Serializable { * @throws NullPointerException if d is null */ public BigMatrixImpl(BigDecimal[][] d) { - int nRows = d.length; - if (nRows == 0) { - throw new IllegalArgumentException( - "Matrix must have at least one row."); - } - int nCols = d[0].length; - if (nCols == 0) { - throw new IllegalArgumentException( - "Matrix must have at least one column."); - } - for (int row = 1; row < nRows; row++) { - if (d[row].length != nCols) { - throw new IllegalArgumentException( - "All input rows must have the same length."); - } - } this.copyIn(d); lu = null; } @@ -503,6 +487,70 @@ public class BigMatrixImpl implements BigMatrix, Serializable { return subMatrix; } + /** + * Replace the submatrix starting at row, column using data in + * the input subMatrix array. Indexes are 0-based. + *

+ * Example:
+ * Starting with

+     * 1  2  3  4
+     * 5  6  7  8
+     * 9  0  1  2
+     * 
+ * and subMatrix = {{3, 4} {5,6}}, invoking + * setSubMatrix(subMatrix,1,1)) will result in
+     * 1  2  3  4
+     * 5  3  4  8
+     * 9  5  6  2
+     * 
+ * + * @param subMatrix array containing the submatrix replacement data + * @param row row coordinate of the top, left element to be replaced + * @param column column coordinate of the top, left element to be replaced + * @throws MatrixIndexException if subMatrix does not fit into this + * matrix from element in (row, column) + * @throws IllegalArgumentException if subMatrix is not rectangular + * (not all rows have the same length) or empty + * @throws NullPointerException if subMatrix is null + */ + public void setSubMatrix(BigDecimal[][] subMatrix, int row, int column) + throws MatrixIndexException { + if ((row < 0) || (column < 0)){ + throw new MatrixIndexException + ("invalid row or column index selection"); + } + int nRows = subMatrix.length; + if (nRows == 0) { + throw new IllegalArgumentException( + "Matrix must have at least one row."); + } + int nCols = subMatrix[0].length; + if (nCols == 0) { + throw new IllegalArgumentException( + "Matrix must have at least one column."); + } + for (int r = 1; r < nRows; r++) { + if (subMatrix[r].length != nCols) { + throw new IllegalArgumentException( + "All input rows must have the same length."); + } + } + if (data == null) { + if ((row > 0)||(column > 0)) throw new MatrixIndexException + ("matrix must be initialized to perfom this method"); + data = new BigDecimal[nRows][nCols]; + System.arraycopy(subMatrix, 0, data, 0, subMatrix.length); + } + if (((nRows + row) > this.getRowDimension()) + || (nCols + column > this.getColumnDimension())) + throw new MatrixIndexException( + "invalid row or column index selection"); + for (int i = 0; i < nRows; i++) { + System.arraycopy(subMatrix[i], 0, data[row + i], column, nCols); + } + lu = null; + } + /** * Returns the entries in row number row * as a row matrix. Row indices start at 0. @@ -1205,18 +1253,16 @@ public class BigMatrixImpl implements BigMatrix, Serializable { /** * Replaces data with a fresh copy of the input array. + *

+ * Verifies that the input array is rectangular and non-empty. * * @param in data to copy in + * @throws IllegalArgumentException if input array is emtpy or not + * rectangular + * @throws NullPointerException if input array is null */ private void copyIn(BigDecimal[][] in) { - int nRows = in.length; - int nCols = in[0].length; - data = new BigDecimal[nRows][nCols]; - System.arraycopy(in, 0, data, 0, in.length); - for (int i = 0; i < nRows; i++) { - System.arraycopy(in[i], 0, data[i], 0, nCols); - } - lu = null; + setSubMatrix(in,0,0); } /** diff --git a/src/java/org/apache/commons/math/linear/RealMatrix.java b/src/java/org/apache/commons/math/linear/RealMatrix.java index e35c6c62c..98c6dfc53 100644 --- a/src/java/org/apache/commons/math/linear/RealMatrix.java +++ b/src/java/org/apache/commons/math/linear/RealMatrix.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 The Apache Software Foundation. + * Copyright 2003-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ package org.apache.commons.math.linear; * @version $Revision$ $Date$ */ public interface RealMatrix { - /** * Returns a (deep) copy of this. * @@ -129,6 +128,35 @@ public interface RealMatrix { RealMatrix getSubMatrix(int[] selectedRows, int[] selectedColumns) throws MatrixIndexException; + /** + * Replace the submatrix starting at row, column using data in + * the input subMatrix array. Indexes are 0-based. + *

+ * Example:
+ * Starting with

+     * 1  2  3  4
+     * 5  6  7  8
+     * 9  0  1  2
+     * 
+ * and subMatrix = {{3, 4} {5,6}}, invoking + * setSubMatrix(subMatrix,1,1)) will result in
+     * 1  2  3  4
+     * 5  3  4  8
+     * 9  5  6  2
+     * 
+ * + * @param subMatrix array containing the submatrix replacement data + * @param row row coordinate of the top, left element to be replaced + * @param column column coordinate of the top, left element to be replaced + * @throws MatrixIndexException if subMatrix does not fit into this + * matrix from element in (row, column) + * @throws IllegalArgumentException if subMatrix is not rectangular + * (not all rows have the same length) or empty + * @throws NullPointerException if subMatrix is null + */ + public void setSubMatrix(double subMatrix[][], int row, int column) throws MatrixIndexException; + + /** * Returns the entries in row number row * as a row matrix. Row indices start at 0. diff --git a/src/java/org/apache/commons/math/linear/RealMatrixImpl.java b/src/java/org/apache/commons/math/linear/RealMatrixImpl.java index e7f370752..f97e9b64c 100644 --- a/src/java/org/apache/commons/math/linear/RealMatrixImpl.java +++ b/src/java/org/apache/commons/math/linear/RealMatrixImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 The Apache Software Foundation. + * Copyright 2003-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -104,22 +104,6 @@ public class RealMatrixImpl implements RealMatrix, Serializable { * @throws NullPointerException if data is null */ public RealMatrixImpl(double[][] d) { - int nRows = d.length; - if (nRows == 0) { - throw new IllegalArgumentException( - "Matrix must have at least one row."); - } - int nCols = d[0].length; - if (nCols == 0) { - throw new IllegalArgumentException( - "Matrix must have at least one column."); - } - for (int row = 1; row < nRows; row++) { - if (d[row].length != nCols) { - throw new IllegalArgumentException( - "All input rows must have the same length."); - } - } this.copyIn(d); lu = null; } @@ -371,12 +355,76 @@ public class RealMatrixImpl implements RealMatrix, Serializable { } return subMatrix; } + + /** + * Replace the submatrix starting at row, column using data in + * the input subMatrix array. Indexes are 0-based. + *

+ * Example:
+ * Starting with

+     * 1  2  3  4
+     * 5  6  7  8
+     * 9  0  1  2
+     * 
+ * and subMatrix = {{3, 4} {5,6}}, invoking + * setSubMatrix(subMatrix,1,1)) will result in
+     * 1  2  3  4
+     * 5  3  4  8
+     * 9  5  6  2
+     * 
+ * + * @param subMatrix array containing the submatrix replacement data + * @param row row coordinate of the top, left element to be replaced + * @param column column coordinate of the top, left element to be replaced + * @throws MatrixIndexException if subMatrix does not fit into this + * matrix from element in (row, column) + * @throws IllegalArgumentException if subMatrix is not rectangular + * (not all rows have the same length) or empty + * @throws NullPointerException if subMatrix is null + */ + public void setSubMatrix(double[][] subMatrix, int row, int column) + throws MatrixIndexException { + if ((row < 0) || (column < 0)){ + throw new MatrixIndexException + ("invalid row or column index selection"); + } + int nRows = subMatrix.length; + if (nRows == 0) { + throw new IllegalArgumentException( + "Matrix must have at least one row."); + } + int nCols = subMatrix[0].length; + if (nCols == 0) { + throw new IllegalArgumentException( + "Matrix must have at least one column."); + } + for (int r = 1; r < nRows; r++) { + if (subMatrix[r].length != nCols) { + throw new IllegalArgumentException( + "All input rows must have the same length."); + } + } + if (data == null) { + if ((row > 0)||(column > 0)) throw new MatrixIndexException + ("matrix must be initialized to perfom this method"); + data = new double[nRows][nCols]; + System.arraycopy(subMatrix, 0, data, 0, subMatrix.length); + } + if (((nRows + row) > this.getRowDimension()) + || (nCols + column > this.getColumnDimension())) + throw new MatrixIndexException( + "invalid row or column index selection"); + for (int i = 0; i < nRows; i++) { + System.arraycopy(subMatrix[i], 0, data[row + i], column, nCols); + } + lu = null; + } /** - * Returns the entries in row number row - * as a row matrix. Row indices start at 0. - * - * @param row the row to be fetched + * Returns the entries in row number row as a row matrix. + * Row indices start at 0. + * + * @param row the row to be fetched * @return row matrix * @throws MatrixIndexException if the specified row index is invalid */ @@ -955,18 +1003,16 @@ public class RealMatrixImpl implements RealMatrix, Serializable { /** * Replaces data with a fresh copy of the input array. + *

+ * Verifies that the input array is rectangular and non-empty * * @param in data to copy in + * @throws IllegalArgumentException if input array is emtpy or not + * rectangular + * @throws NullPointerException if input array is null */ private void copyIn(double[][] in) { - int nRows = in.length; - int nCols = in[0].length; - data = new double[nRows][nCols]; - System.arraycopy(in, 0, data, 0, in.length); - for (int i = 0; i < nRows; i++) { - System.arraycopy(in[i], 0, data[i], 0, nCols); - } - lu = null; + setSubMatrix(in,0,0); } /** diff --git a/src/test/org/apache/commons/math/linear/BigMatrixImplTest.java b/src/test/org/apache/commons/math/linear/BigMatrixImplTest.java index fca288942..2402e47a2 100644 --- a/src/test/org/apache/commons/math/linear/BigMatrixImplTest.java +++ b/src/test/org/apache/commons/math/linear/BigMatrixImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 The Apache Software Foundation. + * Copyright 2004-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -636,6 +636,75 @@ public final class BigMatrixImplTest extends TestCase { m.toString()); } + public void testSetSubMatrix() throws Exception { + BigDecimal[][] detData3 = + MatrixUtils.createBigMatrix(detData2).getData(); + BigMatrixImpl m = new BigMatrixImpl(testData); + m.setSubMatrix(detData3,1,1); + BigMatrix expected = MatrixUtils.createBigMatrix + (new double[][] {{1.0,2.0,3.0},{2.0,1.0,3.0},{1.0,2.0,4.0}}); + assertEquals(expected, m); + + m.setSubMatrix(detData3,0,0); + expected = MatrixUtils.createBigMatrix + (new double[][] {{1.0,3.0,3.0},{2.0,4.0,3.0},{1.0,2.0,4.0}}); + assertEquals(expected, m); + + BigDecimal[][] testDataPlus3 = + MatrixUtils.createBigMatrix(testDataPlus2).getData(); + m.setSubMatrix(testDataPlus3,0,0); + expected = MatrixUtils.createBigMatrix + (new double[][] {{3.0,4.0,5.0},{4.0,7.0,5.0},{3.0,2.0,10.0}}); + assertEquals(expected, m); + + // javadoc example + BigMatrix matrix = MatrixUtils.createBigMatrix + (new double[][] {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 0, 1 , 2}}); + matrix.setSubMatrix(new BigDecimal[][] {{new BigDecimal(3), + new BigDecimal(4)}, {new BigDecimal(5), new BigDecimal(6)}}, 1, 1); + expected = MatrixUtils.createBigMatrix + (new BigDecimal[][] {{new BigDecimal(1), new BigDecimal(2), + new BigDecimal(3), new BigDecimal(4)}, {new BigDecimal(5), + new BigDecimal(3), new BigDecimal(4), new BigDecimal(8)}, + {new BigDecimal(9), new BigDecimal(5) , new BigDecimal(6), + new BigDecimal(2)}}); + assertEquals(expected, matrix); + + // dimension overflow + try { + m.setSubMatrix(matrix.getData(),1,1); + fail("expecting MatrixIndexException"); + } catch (MatrixIndexException e) { + // expected + } + + // null + try { + m.setSubMatrix(null,1,1); + fail("expecting NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + // ragged + try { + m.setSubMatrix(new BigDecimal[][] {{new BigDecimal(1)}, + {new BigDecimal(2), new BigDecimal(3)}}, 0, 0); + fail("expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + // empty + try { + m.setSubMatrix(new BigDecimal[][] {{}}, 0, 0); + fail("expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + } + //--------------- -----------------Protected methods /** verifies that two matrices are close (1-norm) */ diff --git a/src/test/org/apache/commons/math/linear/RealMatrixImplTest.java b/src/test/org/apache/commons/math/linear/RealMatrixImplTest.java index eb69704c2..b25abff9a 100644 --- a/src/test/org/apache/commons/math/linear/RealMatrixImplTest.java +++ b/src/test/org/apache/commons/math/linear/RealMatrixImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 The Apache Software Foundation. + * Copyright 2003-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -610,6 +610,65 @@ public final class RealMatrixImplTest extends TestCase { m.toString()); } + public void testSetSubMatrix() throws Exception { + RealMatrixImpl m = new RealMatrixImpl(testData); + m.setSubMatrix(detData2,1,1); + RealMatrix expected = MatrixUtils.createRealMatrix + (new double[][] {{1.0,2.0,3.0},{2.0,1.0,3.0},{1.0,2.0,4.0}}); + assertEquals(expected, m); + + m.setSubMatrix(detData2,0,0); + expected = MatrixUtils.createRealMatrix + (new double[][] {{1.0,3.0,3.0},{2.0,4.0,3.0},{1.0,2.0,4.0}}); + assertEquals(expected, m); + + m.setSubMatrix(testDataPlus2,0,0); + expected = MatrixUtils.createRealMatrix + (new double[][] {{3.0,4.0,5.0},{4.0,7.0,5.0},{3.0,2.0,10.0}}); + assertEquals(expected, m); + + // javadoc example + RealMatrix matrix = MatrixUtils.createRealMatrix + (new double[][] {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 0, 1 , 2}}); + matrix.setSubMatrix(new double[][] {{3, 4}, {5, 6}}, 1, 1); + expected = MatrixUtils.createRealMatrix + (new double[][] {{1, 2, 3, 4}, {5, 3, 4, 8}, {9, 5 ,6, 2}}); + assertEquals(expected, matrix); + + // dimension overflow + try { + m.setSubMatrix(testData,1,1); + fail("expecting MatrixIndexException"); + } catch (MatrixIndexException e) { + // expected + } + + // null + try { + m.setSubMatrix(null,1,1); + fail("expecting NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + // ragged + try { + m.setSubMatrix(new double[][] {{1}, {2, 3}}, 0, 0); + fail("expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + // empty + try { + m.setSubMatrix(new double[][] {{}}, 0, 0); + fail("expecting IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + } + //--------------- -----------------Protected methods /** verifies that two matrices are close (1-norm) */ diff --git a/xdocs/changes.xml b/xdocs/changes.xml index 5007dd5ce..32d38ec07 100644 --- a/xdocs/changes.xml +++ b/xdocs/changes.xml @@ -39,6 +39,9 @@ The type attribute can be add,update,fix,remove. + + Added setSubMatrix methods to RealMatrix, BigMatrix. + Added createXIdentityMatrix methods to MatrixUtils and deprecated getIdentity methods in RealMatrixImpl, BigMatrixImpl.