1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package org.apache.commons.math.linear; 19 20import java.io.Serializable; 21 22import org.apache.commons.math.Field; 23import org.apache.commons.math.FieldElement; 24import org.apache.commons.math.MathRuntimeException; 25import org.apache.commons.math.linear.MatrixVisitorException; 26import org.apache.commons.math.exception.util.LocalizedFormats; 27 28/** 29 * Implementation of FieldMatrix<T> using a {@link FieldElement}[][] array to store entries. 30 * <p> 31 * As specified in the {@link FieldMatrix} interface, matrix element indexing 32 * is 0-based -- e.g., <code>getEntry(0, 0)</code> 33 * returns the element in the first row, first column of the matrix.</li></ul> 34 * </p> 35 * 36 * @param <T> the type of the field elements 37 * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 févr. 2011) $ 38 */ 39public class Array2DRowFieldMatrix<T extends FieldElement<T>> extends AbstractFieldMatrix<T> implements Serializable { 40 41 /** Serializable version identifier */ 42 private static final long serialVersionUID = 7260756672015356458L; 43 44 /** Entries of the matrix */ 45 protected T[][] data; 46 47 /** 48 * Creates a matrix with no data 49 * @param field field to which the elements belong 50 */ 51 public Array2DRowFieldMatrix(final Field<T> field) { 52 super(field); 53 } 54 55 /** 56 * Create a new FieldMatrix<T> with the supplied row and column dimensions. 57 * 58 * @param field field to which the elements belong 59 * @param rowDimension the number of rows in the new matrix 60 * @param columnDimension the number of columns in the new matrix 61 * @throws IllegalArgumentException if row or column dimension is not 62 * positive 63 */ 64 public Array2DRowFieldMatrix(final Field<T> field, 65 final int rowDimension, final int columnDimension) 66 throws IllegalArgumentException { 67 super(field, rowDimension, columnDimension); 68 data = buildArray(field, rowDimension, columnDimension); 69 } 70 71 /** 72 * Create a new FieldMatrix<T> using the input array as the underlying 73 * data array. 74 * <p>The input array is copied, not referenced. This constructor has 75 * the same effect as calling {@link #Array2DRowFieldMatrix(FieldElement[][], boolean)} 76 * with the second argument set to <code>true</code>.</p> 77 * 78 * @param d data for new matrix 79 * @throws IllegalArgumentException if <code>d</code> is not rectangular 80 * (not all rows have the same length) or empty 81 * @throws NullPointerException if <code>d</code> is null 82 * @see #Array2DRowFieldMatrix(FieldElement[][], boolean) 83 */ 84 public Array2DRowFieldMatrix(final T[][] d) 85 throws IllegalArgumentException, NullPointerException { 86 super(extractField(d)); 87 copyIn(d); 88 } 89 90 /** 91 * Create a new FieldMatrix<T> using the input array as the underlying 92 * data array. 93 * <p>If an array is built specially in order to be embedded in a 94 * FieldMatrix<T> and not used directly, the <code>copyArray</code> may be 95 * set to <code>false</code. This will prevent the copying and improve 96 * performance as no new array will be built and no data will be copied.</p> 97 * @param d data for new matrix 98 * @param copyArray if true, the input array will be copied, otherwise 99 * it will be referenced 100 * @throws IllegalArgumentException if <code>d</code> is not rectangular 101 * (not all rows have the same length) or empty 102 * @throws NullPointerException if <code>d</code> is null 103 * @see #Array2DRowFieldMatrix(FieldElement[][]) 104 */ 105 public Array2DRowFieldMatrix(final T[][] d, final boolean copyArray) 106 throws IllegalArgumentException, NullPointerException { 107 super(extractField(d)); 108 if (copyArray) { 109 copyIn(d); 110 } else { 111 if (d == null) { 112 throw new NullPointerException(); 113 } 114 final int nRows = d.length; 115 if (nRows == 0) { 116 throw MathRuntimeException.createIllegalArgumentException( 117 LocalizedFormats.AT_LEAST_ONE_ROW); 118 } 119 final int nCols = d[0].length; 120 if (nCols == 0) { 121 throw MathRuntimeException.createIllegalArgumentException( 122 LocalizedFormats.AT_LEAST_ONE_COLUMN); 123 } 124 for (int r = 1; r < nRows; r++) { 125 if (d[r].length != nCols) { 126 throw MathRuntimeException.createIllegalArgumentException( 127 LocalizedFormats.DIFFERENT_ROWS_LENGTHS, nCols, d[r].length); 128 } 129 } 130 data = d; 131 } 132 } 133 134 /** 135 * Create a new (column) FieldMatrix<T> using <code>v</code> as the 136 * data for the unique column of the <code>v.length x 1</code> matrix 137 * created. 138 * <p>The input array is copied, not referenced.</p> 139 * 140 * @param v column vector holding data for new matrix 141 */ 142 public Array2DRowFieldMatrix(final T[] v) { 143 super(extractField(v)); 144 final int nRows = v.length; 145 data = buildArray(getField(), nRows, 1); 146 for (int row = 0; row < nRows; row++) { 147 data[row][0] = v[row]; 148 } 149 } 150 151 /** {@inheritDoc} */ 152 @Override 153 public FieldMatrix<T> createMatrix(final int rowDimension, final int columnDimension) 154 throws IllegalArgumentException { 155 return new Array2DRowFieldMatrix<T>(getField(), rowDimension, columnDimension); 156 } 157 158 /** {@inheritDoc} */ 159 @Override 160 public FieldMatrix<T> copy() { 161 return new Array2DRowFieldMatrix<T>(copyOut(), false); 162 } 163 164 /** {@inheritDoc} */ 165 @Override 166 public FieldMatrix<T> add(final FieldMatrix<T> m) 167 throws IllegalArgumentException { 168 try { 169 return add((Array2DRowFieldMatrix<T>) m); 170 } catch (ClassCastException cce) { 171 return super.add(m); 172 } 173 } 174 175 /** 176 * Compute the sum of this and <code>m</code>. 177 * 178 * @param m matrix to be added 179 * @return this + m 180 * @throws IllegalArgumentException if m is not the same size as this 181 */ 182 public Array2DRowFieldMatrix<T> add(final Array2DRowFieldMatrix<T> m) 183 throws IllegalArgumentException { 184 185 // safety check 186 checkAdditionCompatible(m); 187 188 final int rowCount = getRowDimension(); 189 final int columnCount = getColumnDimension(); 190 final T[][] outData = buildArray(getField(), rowCount, columnCount); 191 for (int row = 0; row < rowCount; row++) { 192 final T[] dataRow = data[row]; 193 final T[] mRow = m.data[row]; 194 final T[] outDataRow = outData[row]; 195 for (int col = 0; col < columnCount; col++) { 196 outDataRow[col] = dataRow[col].add(mRow[col]); 197 } 198 } 199 200 return new Array2DRowFieldMatrix<T>(outData, false); 201 202 } 203 204 /** {@inheritDoc} */ 205 @Override 206 public FieldMatrix<T> subtract(final FieldMatrix<T> m) 207 throws IllegalArgumentException { 208 try { 209 return subtract((Array2DRowFieldMatrix<T>) m); 210 } catch (ClassCastException cce) { 211 return super.subtract(m); 212 } 213 } 214 215 /** 216 * Compute this minus <code>m</code>. 217 * 218 * @param m matrix to be subtracted 219 * @return this + m 220 * @throws IllegalArgumentException if m is not the same size as this 221 */ 222 public Array2DRowFieldMatrix<T> subtract(final Array2DRowFieldMatrix<T> m) 223 throws IllegalArgumentException { 224 225 // safety check 226 checkSubtractionCompatible(m); 227 228 final int rowCount = getRowDimension(); 229 final int columnCount = getColumnDimension(); 230 final T[][] outData = buildArray(getField(), rowCount, columnCount); 231 for (int row = 0; row < rowCount; row++) { 232 final T[] dataRow = data[row]; 233 final T[] mRow = m.data[row]; 234 final T[] outDataRow = outData[row]; 235 for (int col = 0; col < columnCount; col++) { 236 outDataRow[col] = dataRow[col].subtract(mRow[col]); 237 } 238 } 239 240 return new Array2DRowFieldMatrix<T>(outData, false); 241 242 } 243 244 /** {@inheritDoc} */ 245 @Override 246 public FieldMatrix<T> multiply(final FieldMatrix<T> m) 247 throws IllegalArgumentException { 248 try { 249 return multiply((Array2DRowFieldMatrix<T>) m); 250 } catch (ClassCastException cce) { 251 return super.multiply(m); 252 } 253 } 254 255 /** 256 * Returns the result of postmultiplying this by <code>m</code>. 257 * @param m matrix to postmultiply by 258 * @return this*m 259 * @throws IllegalArgumentException 260 * if columnDimension(this) != rowDimension(m) 261 */ 262 public Array2DRowFieldMatrix<T> multiply(final Array2DRowFieldMatrix<T> m) 263 throws IllegalArgumentException { 264 265 // safety check 266 checkMultiplicationCompatible(m); 267 268 final int nRows = this.getRowDimension(); 269 final int nCols = m.getColumnDimension(); 270 final int nSum = this.getColumnDimension(); 271 final T[][] outData = buildArray(getField(), nRows, nCols); 272 for (int row = 0; row < nRows; row++) { 273 final T[] dataRow = data[row]; 274 final T[] outDataRow = outData[row]; 275 for (int col = 0; col < nCols; col++) { 276 T sum = getField().getZero(); 277 for (int i = 0; i < nSum; i++) { 278 sum = sum.add(dataRow[i].multiply(m.data[i][col])); 279 } 280 outDataRow[col] = sum; 281 } 282 } 283 284 return new Array2DRowFieldMatrix<T>(outData, false); 285 286 } 287 288 /** {@inheritDoc} */ 289 @Override 290 public T[][] getData() { 291 return copyOut(); 292 } 293 294 /** 295 * Returns a reference to the underlying data array. 296 * <p> 297 * Does <strong>not</strong> make a fresh copy of the underlying data.</p> 298 * 299 * @return 2-dimensional array of entries 300 */ 301 public T[][] getDataRef() { 302 return data; 303 } 304 305 /** {@inheritDoc} */ 306 @Override 307 public void setSubMatrix(final T[][] subMatrix, final int row, final int column) 308 throws MatrixIndexException { 309 if (data == null) { 310 if (row > 0) { 311 throw MathRuntimeException.createIllegalStateException( 312 LocalizedFormats.FIRST_ROWS_NOT_INITIALIZED_YET, row); 313 } 314 if (column > 0) { 315 throw MathRuntimeException.createIllegalStateException( 316 LocalizedFormats.FIRST_COLUMNS_NOT_INITIALIZED_YET, column); 317 } 318 final int nRows = subMatrix.length; 319 if (nRows == 0) { 320 throw MathRuntimeException.createIllegalArgumentException( 321 LocalizedFormats.AT_LEAST_ONE_ROW); 322 } 323 324 final int nCols = subMatrix[0].length; 325 if (nCols == 0) { 326 throw MathRuntimeException.createIllegalArgumentException( 327 LocalizedFormats.AT_LEAST_ONE_COLUMN); 328 } 329 data = buildArray(getField(), subMatrix.length, nCols); 330 for (int i = 0; i < data.length; ++i) { 331 if (subMatrix[i].length != nCols) { 332 throw MathRuntimeException.createIllegalArgumentException( 333 LocalizedFormats.DIFFERENT_ROWS_LENGTHS, nCols, subMatrix[i].length); 334 } 335 System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols); 336 } 337 } else { 338 super.setSubMatrix(subMatrix, row, column); 339 } 340 341 } 342 343 /** {@inheritDoc} */ 344 @Override 345 public T getEntry(final int row, final int column) 346 throws MatrixIndexException { 347 try { 348 return data[row][column]; 349 } catch (ArrayIndexOutOfBoundsException e) { 350 throw new MatrixIndexException( 351 LocalizedFormats.NO_SUCH_MATRIX_ENTRY, row, column, getRowDimension(), getColumnDimension()); 352 } 353 } 354 355 /** {@inheritDoc} */ 356 @Override 357 public void setEntry(final int row, final int column, final T value) 358 throws MatrixIndexException { 359 try { 360 data[row][column] = value; 361 } catch (ArrayIndexOutOfBoundsException e) { 362 throw new MatrixIndexException( 363 LocalizedFormats.NO_SUCH_MATRIX_ENTRY, row, column, getRowDimension(), getColumnDimension()); 364 } 365 } 366 367 /** {@inheritDoc} */ 368 @Override 369 public void addToEntry(final int row, final int column, final T increment) 370 throws MatrixIndexException { 371 try { 372 data[row][column] = data[row][column].add(increment); 373 } catch (ArrayIndexOutOfBoundsException e) { 374 throw new MatrixIndexException( 375 LocalizedFormats.NO_SUCH_MATRIX_ENTRY, row, column, getRowDimension(), getColumnDimension()); 376 } 377 } 378 379 /** {@inheritDoc} */ 380 @Override 381 public void multiplyEntry(final int row, final int column, final T factor) 382 throws MatrixIndexException { 383 try { 384 data[row][column] = data[row][column].multiply(factor); 385 } catch (ArrayIndexOutOfBoundsException e) { 386 throw new MatrixIndexException( 387 LocalizedFormats.NO_SUCH_MATRIX_ENTRY, row, column, getRowDimension(), getColumnDimension()); 388 } 389 } 390 391 /** {@inheritDoc} */ 392 @Override 393 public int getRowDimension() { 394 return (data == null) ? 0 : data.length; 395 } 396 397 /** {@inheritDoc} */ 398 @Override 399 public int getColumnDimension() { 400 return ((data == null) || (data[0] == null)) ? 0 : data[0].length; 401 } 402 403 /** {@inheritDoc} */ 404 @Override 405 public T[] operate(final T[] v) 406 throws IllegalArgumentException { 407 final int nRows = this.getRowDimension(); 408 final int nCols = this.getColumnDimension(); 409 if (v.length != nCols) { 410 throw MathRuntimeException.createIllegalArgumentException( 411 LocalizedFormats.VECTOR_LENGTH_MISMATCH, v.length, nCols); 412 } 413 final T[] out = buildArray(getField(), nRows); 414 for (int row = 0; row < nRows; row++) { 415 final T[] dataRow = data[row]; 416 T sum = getField().getZero(); 417 for (int i = 0; i < nCols; i++) { 418 sum = sum.add(dataRow[i].multiply(v[i])); 419 } 420 out[row] = sum; 421 } 422 return out; 423 } 424 425 /** {@inheritDoc} */ 426 @Override 427 public T[] preMultiply(final T[] v) 428 throws IllegalArgumentException { 429 430 final int nRows = getRowDimension(); 431 final int nCols = getColumnDimension(); 432 if (v.length != nRows) { 433 throw MathRuntimeException.createIllegalArgumentException( 434 LocalizedFormats.VECTOR_LENGTH_MISMATCH, v.length, nRows); 435 } 436 437 final T[] out = buildArray(getField(), nCols); 438 for (int col = 0; col < nCols; ++col) { 439 T sum = getField().getZero(); 440 for (int i = 0; i < nRows; ++i) { 441 sum = sum.add(data[i][col].multiply(v[i])); 442 } 443 out[col] = sum; 444 } 445 446 return out; 447 448 } 449 450 /** {@inheritDoc} */ 451 @Override 452 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor) 453 throws MatrixVisitorException { 454 final int rows = getRowDimension(); 455 final int columns = getColumnDimension(); 456 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 457 for (int i = 0; i < rows; ++i) { 458 final T[] rowI = data[i]; 459 for (int j = 0; j < columns; ++j) { 460 rowI[j] = visitor.visit(i, j, rowI[j]); 461 } 462 } 463 return visitor.end(); 464 } 465 466 /** {@inheritDoc} */ 467 @Override 468 public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor) 469 throws MatrixVisitorException { 470 final int rows = getRowDimension(); 471 final int columns = getColumnDimension(); 472 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 473 for (int i = 0; i < rows; ++i) { 474 final T[] rowI = data[i]; 475 for (int j = 0; j < columns; ++j) { 476 visitor.visit(i, j, rowI[j]); 477 } 478 } 479 return visitor.end(); 480 } 481 482 /** {@inheritDoc} */ 483 @Override 484 public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor, 485 final int startRow, final int endRow, 486 final int startColumn, final int endColumn) 487 throws MatrixIndexException, MatrixVisitorException { 488 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 489 visitor.start(getRowDimension(), getColumnDimension(), 490 startRow, endRow, startColumn, endColumn); 491 for (int i = startRow; i <= endRow; ++i) { 492 final T[] rowI = data[i]; 493 for (int j = startColumn; j <= endColumn; ++j) { 494 rowI[j] = visitor.visit(i, j, rowI[j]); 495 } 496 } 497 return visitor.end(); 498 } 499 500 /** {@inheritDoc} */ 501 @Override 502 public T walkInRowOrder(final FieldMatrixPreservingVisitor<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 visitor.visit(i, j, rowI[j]); 513 } 514 } 515 return visitor.end(); 516 } 517 518 /** {@inheritDoc} */ 519 @Override 520 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor) 521 throws MatrixVisitorException { 522 final int rows = getRowDimension(); 523 final int columns = getColumnDimension(); 524 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 525 for (int j = 0; j < columns; ++j) { 526 for (int i = 0; i < rows; ++i) { 527 final T[] rowI = data[i]; 528 rowI[j] = visitor.visit(i, j, rowI[j]); 529 } 530 } 531 return visitor.end(); 532 } 533 534 /** {@inheritDoc} */ 535 @Override 536 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor) 537 throws MatrixVisitorException { 538 final int rows = getRowDimension(); 539 final int columns = getColumnDimension(); 540 visitor.start(rows, columns, 0, rows - 1, 0, columns - 1); 541 for (int j = 0; j < columns; ++j) { 542 for (int i = 0; i < rows; ++i) { 543 visitor.visit(i, j, data[i][j]); 544 } 545 } 546 return visitor.end(); 547 } 548 549 /** {@inheritDoc} */ 550 @Override 551 public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor, 552 final int startRow, final int endRow, 553 final int startColumn, final int endColumn) 554 throws MatrixIndexException, MatrixVisitorException { 555 checkSubMatrixIndex(startRow, endRow, startColumn, endColumn); 556 visitor.start(getRowDimension(), getColumnDimension(), 557 startRow, endRow, startColumn, endColumn); 558 for (int j = startColumn; j <= endColumn; ++j) { 559 for (int i = startRow; i <= endRow; ++i) { 560 final T[] rowI = data[i]; 561 rowI[j] = visitor.visit(i, j, rowI[j]); 562 } 563 } 564 return visitor.end(); 565 } 566 567 /** {@inheritDoc} */ 568 @Override 569 public T walkInColumnOrder(final FieldMatrixPreservingVisitor<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 visitor.visit(i, j, data[i][j]); 579 } 580 } 581 return visitor.end(); 582 } 583 584 /** 585 * Returns a fresh copy of the underlying data array. 586 * 587 * @return a copy of the underlying data array. 588 */ 589 private T[][] copyOut() { 590 final int nRows = this.getRowDimension(); 591 final T[][] out = buildArray(getField(), nRows, getColumnDimension()); 592 // can't copy 2-d array in one shot, otherwise get row references 593 for (int i = 0; i < nRows; i++) { 594 System.arraycopy(data[i], 0, out[i], 0, data[i].length); 595 } 596 return out; 597 } 598 599 /** 600 * Replaces data with a fresh copy of the input array. 601 * <p> 602 * Verifies that the input array is rectangular and non-empty.</p> 603 * 604 * @param in data to copy in 605 * @throws IllegalArgumentException if input array is empty or not 606 * rectangular 607 * @throws NullPointerException if input array is null 608 */ 609 private void copyIn(final T[][] in) { 610 setSubMatrix(in, 0, 0); 611 } 612 613} 614