001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.math.linear; 019 020 import java.io.Serializable; 021 022 import org.apache.commons.math.Field; 023 import org.apache.commons.math.FieldElement; 024 import org.apache.commons.math.MathRuntimeException; 025 026 /** 027 * Implementation of FieldMatrix<T> using a {@link FieldElement}[][] array to store entries. 028 * <p> 029 * As specified in the {@link FieldMatrix} interface, matrix element indexing 030 * is 0-based -- e.g., <code>getEntry(0, 0)</code> 031 * returns the element in the first row, first column of the matrix.</li></ul> 032 * </p> 033 * 034 * @param <T> the type of the field elements 035 * @version $Revision: 885278 $ $Date: 2009-11-29 16:47:51 -0500 (Sun, 29 Nov 2009) $ 036 */ 037 public class Array2DRowFieldMatrix<T extends FieldElement<T>> extends AbstractFieldMatrix<T> implements Serializable { 038 039 /** Serializable version identifier */ 040 private static final long serialVersionUID = 7260756672015356458L; 041 042 /** Message for at least one row. */ 043 private static final String AT_LEAST_ONE_ROW_MESSAGE = 044 "matrix must have at least one row"; 045 046 /** Message for at least one column. */ 047 private static final String AT_LEAST_ONE_COLUMN_MESSAGE = 048 "matrix must have at least one column"; 049 050 /** Message for different rows lengths. */ 051 private static final String DIFFERENT_ROWS_LENGTHS_MESSAGE = 052 "some rows have length {0} while others have length {1}"; 053 054 /** Message for no entry at selected indices. */ 055 private static final String NO_ENTRY_MESSAGE = 056 "no entry at indices ({0}, {1}) in a {2}x{3} matrix"; 057 058 /** Message for vector lengths mismatch. */ 059 private static final String VECTOR_LENGTHS_MISMATCH = 060 "vector length mismatch: got {0} but expected {1}"; 061 062 /** Entries of the matrix */ 063 protected T[][] data; 064 065 /** 066 * Creates a matrix with no data 067 * @param field field to which the elements belong 068 */ 069 public Array2DRowFieldMatrix(final Field<T> field) { 070 super(field); 071 } 072 073 /** 074 * Create a new FieldMatrix<T> with the supplied row and column dimensions. 075 * 076 * @param field field to which the elements belong 077 * @param rowDimension the number of rows in the new matrix 078 * @param columnDimension the number of columns in the new matrix 079 * @throws IllegalArgumentException if row or column dimension is not 080 * positive 081 */ 082 public Array2DRowFieldMatrix(final Field<T> field, 083 final int rowDimension, final int columnDimension) 084 throws IllegalArgumentException { 085 super(field, rowDimension, columnDimension); 086 data = buildArray(field, rowDimension, columnDimension); 087 } 088 089 /** 090 * Create a new FieldMatrix<T> using the input array as the underlying 091 * data array. 092 * <p>The input array is copied, not referenced. This constructor has 093 * the same effect as calling {@link #Array2DRowFieldMatrix(FieldElement[][], boolean)} 094 * with the second argument set to <code>true</code>.</p> 095 * 096 * @param d data for new matrix 097 * @throws IllegalArgumentException if <code>d</code> is not rectangular 098 * (not all rows have the same length) or empty 099 * @throws NullPointerException if <code>d</code> is null 100 * @see #Array2DRowFieldMatrix(FieldElement[][], boolean) 101 */ 102 public Array2DRowFieldMatrix(final T[][] d) 103 throws IllegalArgumentException, NullPointerException { 104 super(extractField(d)); 105 copyIn(d); 106 } 107 108 /** 109 * Create a new FieldMatrix<T> using the input array as the underlying 110 * data array. 111 * <p>If an array is built specially in order to be embedded in a 112 * FieldMatrix<T> and not used directly, the <code>copyArray</code> may be 113 * set to <code>false</code. This will prevent the copying and improve 114 * performance as no new array will be built and no data will be copied.</p> 115 * @param d data for new matrix 116 * @param copyArray if true, the input array will be copied, otherwise 117 * it will be referenced 118 * @throws IllegalArgumentException if <code>d</code> is not rectangular 119 * (not all rows have the same length) or empty 120 * @throws NullPointerException if <code>d</code> is null 121 * @see #Array2DRowFieldMatrix(FieldElement[][]) 122 */ 123 public Array2DRowFieldMatrix(final T[][] d, final boolean copyArray) 124 throws IllegalArgumentException, NullPointerException { 125 super(extractField(d)); 126 if (copyArray) { 127 copyIn(d); 128 } else { 129 if (d == null) { 130 throw new NullPointerException(); 131 } 132 final int nRows = d.length; 133 if (nRows == 0) { 134 throw MathRuntimeException.createIllegalArgumentException( 135 AT_LEAST_ONE_ROW_MESSAGE); 136 } 137 final int nCols = d[0].length; 138 if (nCols == 0) { 139 throw MathRuntimeException.createIllegalArgumentException( 140 AT_LEAST_ONE_COLUMN_MESSAGE); 141 } 142 for (int r = 1; r < nRows; r++) { 143 if (d[r].length != nCols) { 144 throw MathRuntimeException.createIllegalArgumentException( 145 DIFFERENT_ROWS_LENGTHS_MESSAGE, nCols, d[r].length); 146 } 147 } 148 data = d; 149 } 150 } 151 152 /** 153 * Create a new (column) FieldMatrix<T> using <code>v</code> as the 154 * data for the unique column of the <code>v.length x 1</code> matrix 155 * created. 156 * <p>The input array is copied, not referenced.</p> 157 * 158 * @param v column vector holding data for new matrix 159 */ 160 public Array2DRowFieldMatrix(final T[] v) { 161 super(extractField(v)); 162 final int nRows = v.length; 163 data = buildArray(getField(), nRows, 1); 164 for (int row = 0; row < nRows; row++) { 165 data[row][0] = v[row]; 166 } 167 } 168 169 /** {@inheritDoc} */ 170 @Override 171 public FieldMatrix<T> createMatrix(final int rowDimension, final int columnDimension) 172 throws IllegalArgumentException { 173 return new Array2DRowFieldMatrix<T>(getField(), rowDimension, columnDimension); 174 } 175 176 /** {@inheritDoc} */ 177 @Override 178 public FieldMatrix<T> copy() { 179 return new Array2DRowFieldMatrix<T>(copyOut(), false); 180 } 181 182 /** {@inheritDoc} */ 183 @Override 184 public FieldMatrix<T> add(final FieldMatrix<T> m) 185 throws IllegalArgumentException { 186 try { 187 return add((Array2DRowFieldMatrix<T>) m); 188 } catch (ClassCastException cce) { 189 return super.add(m); 190 } 191 } 192 193 /** 194 * Compute the sum of this and <code>m</code>. 195 * 196 * @param m matrix to be added 197 * @return this + m 198 * @throws IllegalArgumentException if m is not the same size as this 199 */ 200 public Array2DRowFieldMatrix<T> add(final Array2DRowFieldMatrix<T> m) 201 throws IllegalArgumentException { 202 203 // safety check 204 checkAdditionCompatible(m); 205 206 final int rowCount = getRowDimension(); 207 final int columnCount = getColumnDimension(); 208 final T[][] outData = buildArray(getField(), rowCount, columnCount); 209 for (int row = 0; row < rowCount; row++) { 210 final T[] dataRow = data[row]; 211 final T[] mRow = m.data[row]; 212 final T[] outDataRow = outData[row]; 213 for (int col = 0; col < columnCount; col++) { 214 outDataRow[col] = dataRow[col].add(mRow[col]); 215 } 216 } 217 218 return new Array2DRowFieldMatrix<T>(outData, false); 219 220 } 221 222 /** {@inheritDoc} */ 223 @Override 224 public FieldMatrix<T> subtract(final FieldMatrix<T> m) 225 throws IllegalArgumentException { 226 try { 227 return subtract((Array2DRowFieldMatrix<T>) m); 228 } catch (ClassCastException cce) { 229 return super.subtract(m); 230 } 231 } 232 233 /** 234 * Compute this minus <code>m</code>. 235 * 236 * @param m matrix to be subtracted 237 * @return this + m 238 * @throws IllegalArgumentException if m is not the same size as this 239 */ 240 public Array2DRowFieldMatrix<T> subtract(final Array2DRowFieldMatrix<T> m) 241 throws IllegalArgumentException { 242 243 // safety check 244 checkSubtractionCompatible(m); 245 246 final int rowCount = getRowDimension(); 247 final int columnCount = getColumnDimension(); 248 final T[][] outData = buildArray(getField(), rowCount, columnCount); 249 for (int row = 0; row < rowCount; row++) { 250 final T[] dataRow = data[row]; 251 final T[] mRow = m.data[row]; 252 final T[] outDataRow = outData[row]; 253 for (int col = 0; col < columnCount; col++) { 254 outDataRow[col] = dataRow[col].subtract(mRow[col]); 255 } 256 } 257 258 return new Array2DRowFieldMatrix<T>(outData, false); 259 260 } 261 262 /** {@inheritDoc} */ 263 @Override 264 public FieldMatrix<T> multiply(final FieldMatrix<T> m) 265 throws IllegalArgumentException { 266 try { 267 return multiply((Array2DRowFieldMatrix<T>) m); 268 } catch (ClassCastException cce) { 269 return super.multiply(m); 270 } 271 } 272 273 /** 274 * Returns the result of postmultiplying this by <code>m</code>. 275 * @param m matrix to postmultiply by 276 * @return this*m 277 * @throws IllegalArgumentException 278 * if columnDimension(this) != rowDimension(m) 279 */ 280 public Array2DRowFieldMatrix<T> multiply(final Array2DRowFieldMatrix<T> m) 281 throws IllegalArgumentException { 282 283 // safety check 284 checkMultiplicationCompatible(m); 285 286 final int nRows = this.getRowDimension(); 287 final int nCols = m.getColumnDimension(); 288 final int nSum = this.getColumnDimension(); 289 final T[][] outData = buildArray(getField(), nRows, nCols); 290 for (int row = 0; row < nRows; row++) { 291 final T[] dataRow = data[row]; 292 final T[] outDataRow = outData[row]; 293 for (int col = 0; col < nCols; col++) { 294 T sum = getField().getZero(); 295 for (int i = 0; i < nSum; i++) { 296 sum = sum.add(dataRow[i].multiply(m.data[i][col])); 297 } 298 outDataRow[col] = sum; 299 } 300 } 301 302 return new Array2DRowFieldMatrix<T>(outData, false); 303 304 } 305 306 /** {@inheritDoc} */ 307 @Override 308 public T[][] getData() { 309 return copyOut(); 310 } 311 312 /** 313 * Returns a reference to the underlying data array. 314 * <p> 315 * Does <strong>not</strong> make a fresh copy of the underlying data.</p> 316 * 317 * @return 2-dimensional array of entries 318 */ 319 public T[][] getDataRef() { 320 return data; 321 } 322 323 /** {@inheritDoc} */ 324 @Override 325 public void setSubMatrix(final T[][] subMatrix, final int row, final int column) 326 throws MatrixIndexException { 327 if (data == null) { 328 if (row > 0) { 329 throw MathRuntimeException.createIllegalStateException( 330 "first {0} rows are not initialized yet", row); 331 } 332 if (column > 0) { 333 throw MathRuntimeException.createIllegalStateException( 334 "first {0} columns are not initialized yet", column); 335 } 336 final int nRows = subMatrix.length; 337 if (nRows == 0) { 338 throw MathRuntimeException.createIllegalArgumentException( 339 AT_LEAST_ONE_ROW_MESSAGE); 340 } 341 342 final int nCols = subMatrix[0].length; 343 if (nCols == 0) { 344 throw MathRuntimeException.createIllegalArgumentException( 345 AT_LEAST_ONE_COLUMN_MESSAGE); 346 } 347 data = buildArray(getField(), subMatrix.length, nCols); 348 for (int i = 0; i < data.length; ++i) { 349 if (subMatrix[i].length != nCols) { 350 throw MathRuntimeException.createIllegalArgumentException( 351 DIFFERENT_ROWS_LENGTHS_MESSAGE, nCols, subMatrix[i].length); 352 } 353 System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols); 354 } 355 } else { 356 super.setSubMatrix(subMatrix, row, column); 357 } 358 359 } 360 361 /** {@inheritDoc} */ 362 @Override 363 public T getEntry(final int row, final int column) 364 throws MatrixIndexException { 365 try { 366 return data[row][column]; 367 } catch (ArrayIndexOutOfBoundsException e) { 368 throw new MatrixIndexException( 369 NO_ENTRY_MESSAGE, row, column, getRowDimension(), getColumnDimension()); 370 } 371 } 372 373 /** {@inheritDoc} */ 374 @Override 375 public void setEntry(final int row, final int column, final T value) 376 throws MatrixIndexException { 377 try { 378 data[row][column] = value; 379 } catch (ArrayIndexOutOfBoundsException e) { 380 throw new MatrixIndexException( 381 NO_ENTRY_MESSAGE, row, column, getRowDimension(), getColumnDimension()); 382 } 383 } 384 385 /** {@inheritDoc} */ 386 @Override 387 public void addToEntry(final int row, final int column, final T increment) 388 throws MatrixIndexException { 389 try { 390 data[row][column] = data[row][column].add(increment); 391 } catch (ArrayIndexOutOfBoundsException e) { 392 throw new MatrixIndexException( 393 NO_ENTRY_MESSAGE, row, column, getRowDimension(), getColumnDimension()); 394 } 395 } 396 397 /** {@inheritDoc} */ 398 @Override 399 public void multiplyEntry(final int row, final int column, final T factor) 400 throws MatrixIndexException { 401 try { 402 data[row][column] = data[row][column].multiply(factor); 403 } catch (ArrayIndexOutOfBoundsException e) { 404 throw new MatrixIndexException( 405 NO_ENTRY_MESSAGE, row, column, getRowDimension(), getColumnDimension()); 406 } 407 } 408 409 /** {@inheritDoc} */ 410 @Override 411 public int getRowDimension() { 412 return (data == null) ? 0 : data.length; 413 } 414 415 /** {@inheritDoc} */ 416 @Override 417 public int getColumnDimension() { 418 return ((data == null) || (data[0] == null)) ? 0 : data[0].length; 419 } 420 421 /** {@inheritDoc} */ 422 @Override 423 public T[] operate(final T[] v) 424 throws IllegalArgumentException { 425 final int nRows = this.getRowDimension(); 426 final int nCols = this.getColumnDimension(); 427 if (v.length != nCols) { 428 throw MathRuntimeException.createIllegalArgumentException( 429 VECTOR_LENGTHS_MISMATCH, v.length, nCols); 430 } 431 final T[] out = buildArray(getField(), nRows); 432 for (int row = 0; row < nRows; row++) { 433 final T[] dataRow = data[row]; 434 T sum = getField().getZero(); 435 for (int i = 0; i < nCols; i++) { 436 sum = sum.add(dataRow[i].multiply(v[i])); 437 } 438 out[row] = sum; 439 } 440 return out; 441 } 442 443 /** {@inheritDoc} */ 444 @Override 445 public T[] preMultiply(final T[] v) 446 throws IllegalArgumentException { 447 448 final int nRows = getRowDimension(); 449 final int nCols = getColumnDimension(); 450 if (v.length != nRows) { 451 throw MathRuntimeException.createIllegalArgumentException( 452 VECTOR_LENGTHS_MISMATCH, v.length, nRows); 453 } 454 455 final T[] out = buildArray(getField(), nCols); 456 for (int col = 0; col < nCols; ++col) { 457 T sum = getField().getZero(); 458 for (int i = 0; i < nRows; ++i) { 459 sum = sum.add(data[i][col].multiply(v[i])); 460 } 461 out[col] = sum; 462 } 463 464 return out; 465 466 } 467 468 /** {@inheritDoc} */ 469 @Override 470 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor) 471 throws MatrixVisitorException { 472 final int rows = getRowDimension(); 473 final int columns = getColumnDimension(); 474 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 475 for (int i = 0; i < rows; ++i) { 476 final T[] rowI = data[i]; 477 for (int j = 0; j < columns; ++j) { 478 rowI[j] = visitor.visit(i, j, rowI[j]); 479 } 480 } 481 return visitor.end(); 482 } 483 484 /** {@inheritDoc} */ 485 @Override 486 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor) 487 throws MatrixVisitorException { 488 final int rows = getRowDimension(); 489 final int columns = getColumnDimension(); 490 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 491 for (int i = 0; i < rows; ++i) { 492 final T[] rowI = data[i]; 493 for (int j = 0; j < columns; ++j) { 494 visitor.visit(i, j, rowI[j]); 495 } 496 } 497 return visitor.end(); 498 } 499 500 /** {@inheritDoc} */ 501 @Override 502 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor, 503 final int startRow, final int endRow, 504 final int startColumn, final int endColumn) 505 throws MatrixIndexException, MatrixVisitorException { 506 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 507 visitor.start(getRowDimension(), getColumnDimension(), 508 startRow, endRow, startColumn, endColumn); 509 for (int i = startRow; i <= endRow; ++i) { 510 final T[] rowI = data[i]; 511 for (int j = startColumn; j <= endColumn; ++j) { 512 rowI[j] = visitor.visit(i, j, rowI[j]); 513 } 514 } 515 return visitor.end(); 516 } 517 518 /** {@inheritDoc} */ 519 @Override 520 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor, 521 final int startRow, final int endRow, 522 final int startColumn, final int endColumn) 523 throws MatrixIndexException, MatrixVisitorException { 524 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 525 visitor.start(getRowDimension(), getColumnDimension(), 526 startRow, endRow, startColumn, endColumn); 527 for (int i = startRow; i <= endRow; ++i) { 528 final T[] rowI = data[i]; 529 for (int j = startColumn; j <= endColumn; ++j) { 530 visitor.visit(i, j, rowI[j]); 531 } 532 } 533 return visitor.end(); 534 } 535 536 /** {@inheritDoc} */ 537 @Override 538 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor) 539 throws MatrixVisitorException { 540 final int rows = getRowDimension(); 541 final int columns = getColumnDimension(); 542 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 543 for (int j = 0; j < columns; ++j) { 544 for (int i = 0; i < rows; ++i) { 545 final T[] rowI = data[i]; 546 rowI[j] = visitor.visit(i, j, rowI[j]); 547 } 548 } 549 return visitor.end(); 550 } 551 552 /** {@inheritDoc} */ 553 @Override 554 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor) 555 throws MatrixVisitorException { 556 final int rows = getRowDimension(); 557 final int columns = getColumnDimension(); 558 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 559 for (int j = 0; j < columns; ++j) { 560 for (int i = 0; i < rows; ++i) { 561 visitor.visit(i, j, data[i][j]); 562 } 563 } 564 return visitor.end(); 565 } 566 567 /** {@inheritDoc} */ 568 @Override 569 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor, 570 final int startRow, final int endRow, 571 final int startColumn, final int endColumn) 572 throws MatrixIndexException, MatrixVisitorException { 573 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 574 visitor.start(getRowDimension(), getColumnDimension(), 575 startRow, endRow, startColumn, endColumn); 576 for (int j = startColumn; j <= endColumn; ++j) { 577 for (int i = startRow; i <= endRow; ++i) { 578 final T[] rowI = data[i]; 579 rowI[j] = visitor.visit(i, j, rowI[j]); 580 } 581 } 582 return visitor.end(); 583 } 584 585 /** {@inheritDoc} */ 586 @Override 587 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor, 588 final int startRow, final int endRow, 589 final int startColumn, final int endColumn) 590 throws MatrixIndexException, MatrixVisitorException { 591 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 592 visitor.start(getRowDimension(), getColumnDimension(), 593 startRow, endRow, startColumn, endColumn); 594 for (int j = startColumn; j <= endColumn; ++j) { 595 for (int i = startRow; i <= endRow; ++i) { 596 visitor.visit(i, j, data[i][j]); 597 } 598 } 599 return visitor.end(); 600 } 601 602 /** 603 * Returns a fresh copy of the underlying data array. 604 * 605 * @return a copy of the underlying data array. 606 */ 607 private T[][] copyOut() { 608 final int nRows = this.getRowDimension(); 609 final T[][] out = buildArray(getField(), nRows, getColumnDimension()); 610 // can't copy 2-d array in one shot, otherwise get row references 611 for (int i = 0; i < nRows; i++) { 612 System.arraycopy(data[i], 0, out[i], 0, data[i].length); 613 } 614 return out; 615 } 616 617 /** 618 * Replaces data with a fresh copy of the input array. 619 * <p> 620 * Verifies that the input array is rectangular and non-empty.</p> 621 * 622 * @param in data to copy in 623 * @throws IllegalArgumentException if input array is empty or not 624 * rectangular 625 * @throws NullPointerException if input array is null 626 */ 627 private void copyIn(final T[][] in) { 628 setSubMatrix(in, 0, 0); 629 } 630 631 }