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