001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.math; 006 007import edu.wpi.first.math.jni.EigenJNI; 008import edu.wpi.first.math.numbers.N1; 009import edu.wpi.first.math.proto.MatrixProto; 010import edu.wpi.first.math.struct.MatrixStruct; 011import edu.wpi.first.util.protobuf.Protobuf; 012import edu.wpi.first.util.protobuf.ProtobufSerializable; 013import edu.wpi.first.util.struct.Struct; 014import edu.wpi.first.util.struct.StructSerializable; 015import java.util.Objects; 016import org.ejml.MatrixDimensionException; 017import org.ejml.data.DMatrixRMaj; 018import org.ejml.dense.row.CommonOps_DDRM; 019import org.ejml.dense.row.MatrixFeatures_DDRM; 020import org.ejml.dense.row.NormOps_DDRM; 021import org.ejml.dense.row.factory.DecompositionFactory_DDRM; 022import org.ejml.interfaces.decomposition.CholeskyDecomposition_F64; 023import org.ejml.simple.SimpleMatrix; 024 025/** 026 * A shape-safe wrapper over Efficient Java Matrix Library (EJML) matrices. 027 * 028 * <p>This class is intended to be used alongside the state space library. 029 * 030 * @param <R> The number of rows in this matrix. 031 * @param <C> The number of columns in this matrix. 032 */ 033public class Matrix<R extends Num, C extends Num> 034 implements ProtobufSerializable, StructSerializable { 035 /** Storage for underlying EJML matrix. */ 036 protected final SimpleMatrix m_storage; 037 038 /** 039 * Constructs an empty zero matrix of the given dimensions. 040 * 041 * @param rows The number of rows of the matrix. 042 * @param columns The number of columns of the matrix. 043 */ 044 public Matrix(Nat<R> rows, Nat<C> columns) { 045 this.m_storage = 046 new SimpleMatrix( 047 Objects.requireNonNull(rows).getNum(), Objects.requireNonNull(columns).getNum()); 048 } 049 050 /** 051 * Constructs a new {@link Matrix} with the given storage. Caller should make sure that the 052 * provided generic bounds match the shape of the provided {@link Matrix}. 053 * 054 * @param rows The number of rows of the matrix. 055 * @param columns The number of columns of the matrix. 056 * @param storage The double array to back this value. 057 */ 058 public Matrix(Nat<R> rows, Nat<C> columns, double[] storage) { 059 this.m_storage = new SimpleMatrix(rows.getNum(), columns.getNum(), true, storage); 060 } 061 062 /** 063 * Constructs a new {@link Matrix} with the given storage. Caller should make sure that the 064 * provided generic bounds match the shape of the provided {@link Matrix}. 065 * 066 * <p>NOTE:It is not recommend to use this constructor unless the {@link SimpleMatrix} API is 067 * absolutely necessary due to the desired function not being accessible through the {@link 068 * Matrix} wrapper. 069 * 070 * @param storage The {@link SimpleMatrix} to back this value. 071 */ 072 public Matrix(SimpleMatrix storage) { 073 this.m_storage = Objects.requireNonNull(storage); 074 } 075 076 /** 077 * Constructs a new matrix with the storage of the supplied matrix. 078 * 079 * @param other The {@link Matrix} to copy the storage of. 080 */ 081 public Matrix(Matrix<R, C> other) { 082 this.m_storage = Objects.requireNonNull(other).getStorage().copy(); 083 } 084 085 /** 086 * Gets the underlying {@link SimpleMatrix} that this {@link Matrix} wraps. 087 * 088 * <p>NOTE:The use of this method is heavily discouraged as this removes any guarantee of type 089 * safety. This should only be called if the {@link SimpleMatrix} API is absolutely necessary due 090 * to the desired function not being accessible through the {@link Matrix} wrapper. 091 * 092 * @return The underlying {@link SimpleMatrix} storage. 093 */ 094 public SimpleMatrix getStorage() { 095 return m_storage; 096 } 097 098 /** 099 * Gets the number of columns in this matrix. 100 * 101 * @return The number of columns, according to the internal storage. 102 */ 103 public final int getNumCols() { 104 return this.m_storage.getNumCols(); 105 } 106 107 /** 108 * Gets the number of rows in this matrix. 109 * 110 * @return The number of rows, according to the internal storage. 111 */ 112 public final int getNumRows() { 113 return this.m_storage.getNumRows(); 114 } 115 116 /** 117 * Get an element of this matrix. 118 * 119 * @param row The row of the element. 120 * @param col The column of the element. 121 * @return The element in this matrix at row,col. 122 */ 123 public final double get(int row, int col) { 124 return this.m_storage.get(row, col); 125 } 126 127 /** 128 * Sets the value at the given indices. 129 * 130 * @param row The row of the element. 131 * @param col The column of the element. 132 * @param value The value to insert at the given location. 133 */ 134 public final void set(int row, int col, double value) { 135 this.m_storage.set(row, col, value); 136 } 137 138 /** 139 * Sets a row to a given row vector. 140 * 141 * @param row The row to set. 142 * @param val The row vector to set the given row to. 143 */ 144 public final void setRow(int row, Matrix<N1, C> val) { 145 this.m_storage.setRow(row, 0, Objects.requireNonNull(val).m_storage.getDDRM().getData()); 146 } 147 148 /** 149 * Sets a column to a given column vector. 150 * 151 * @param column The column to set. 152 * @param val The column vector to set the given row to. 153 */ 154 public final void setColumn(int column, Matrix<R, N1> val) { 155 this.m_storage.setColumn(column, 0, Objects.requireNonNull(val).m_storage.getDDRM().getData()); 156 } 157 158 /** 159 * Sets all the elements in "this" matrix equal to the specified value. 160 * 161 * @param value The value each element is set to. 162 */ 163 public void fill(double value) { 164 this.m_storage.fill(value); 165 } 166 167 /** 168 * Returns the diagonal elements inside a vector or square matrix. 169 * 170 * <p>If "this" {@link Matrix} is a vector then a square matrix is returned. If a "this" {@link 171 * Matrix} is a matrix then a vector of diagonal elements is returned. 172 * 173 * @return The diagonal elements inside a vector or a square matrix. 174 */ 175 public final Matrix<R, C> diag() { 176 return new Matrix<>(this.m_storage.diag()); 177 } 178 179 /** 180 * Returns the largest element of this matrix. 181 * 182 * @return The largest element of this matrix. 183 */ 184 public final double max() { 185 return CommonOps_DDRM.elementMax(this.m_storage.getDDRM()); 186 } 187 188 /** 189 * Returns the absolute value of the element in this matrix with the largest absolute value. 190 * 191 * @return The absolute value of the element with the largest absolute value. 192 */ 193 public final double maxAbs() { 194 return CommonOps_DDRM.elementMaxAbs(this.m_storage.getDDRM()); 195 } 196 197 /** 198 * Returns the smallest element of this matrix. 199 * 200 * @return The smallest element of this matrix. 201 */ 202 public final double minInternal() { 203 return CommonOps_DDRM.elementMin(this.m_storage.getDDRM()); 204 } 205 206 /** 207 * Calculates the mean of the elements in this matrix. 208 * 209 * @return The mean value of this matrix. 210 */ 211 public final double mean() { 212 return this.elementSum() / this.m_storage.getNumElements(); 213 } 214 215 /** 216 * Multiplies this matrix with another that has C rows. 217 * 218 * <p>As matrix multiplication is only defined if the number of columns in the first matrix 219 * matches the number of rows in the second, this operation will fail to compile under any other 220 * circumstances. 221 * 222 * @param other The other matrix to multiply by. 223 * @param <C2> The number of columns in the second matrix. 224 * @return The result of the matrix multiplication between "this" and the given matrix. 225 */ 226 public final <C2 extends Num> Matrix<R, C2> times(Matrix<C, C2> other) { 227 return new Matrix<>(this.m_storage.mult(Objects.requireNonNull(other).m_storage)); 228 } 229 230 /** 231 * Multiplies all the elements of this matrix by the given scalar. 232 * 233 * @param value The scalar value to multiply by. 234 * @return A new matrix with all the elements multiplied by the given value. 235 */ 236 public Matrix<R, C> times(double value) { 237 return new Matrix<>(this.m_storage.scale(value)); 238 } 239 240 /** 241 * Returns a matrix which is the result of an element by element multiplication of "this" and 242 * other. 243 * 244 * <p>c<sub>i,j</sub> = a<sub>i,j</sub>*other<sub>i,j</sub> 245 * 246 * @param other The other {@link Matrix} to perform element multiplication on. 247 * @return The element by element multiplication of "this" and other. 248 */ 249 public final Matrix<R, C> elementTimes(Matrix<R, C> other) { 250 return new Matrix<>(this.m_storage.elementMult(Objects.requireNonNull(other).m_storage)); 251 } 252 253 /** 254 * Subtracts the given value from all the elements of this matrix. 255 * 256 * @param value The value to subtract. 257 * @return The resultant matrix. 258 */ 259 public final Matrix<R, C> minus(double value) { 260 return new Matrix<>(this.m_storage.minus(value)); 261 } 262 263 /** 264 * Subtracts the given matrix from this matrix. 265 * 266 * @param value The matrix to subtract. 267 * @return The resultant matrix. 268 */ 269 public final Matrix<R, C> minus(Matrix<R, C> value) { 270 return new Matrix<>(this.m_storage.minus(Objects.requireNonNull(value).m_storage)); 271 } 272 273 /** 274 * Adds the given value to all the elements of this matrix. 275 * 276 * @param value The value to add. 277 * @return The resultant matrix. 278 */ 279 public final Matrix<R, C> plus(double value) { 280 return new Matrix<>(this.m_storage.plus(value)); 281 } 282 283 /** 284 * Adds the given matrix to this matrix. 285 * 286 * @param value The matrix to add. 287 * @return The resultant matrix. 288 */ 289 public final Matrix<R, C> plus(Matrix<R, C> value) { 290 return new Matrix<>(this.m_storage.plus(Objects.requireNonNull(value).m_storage)); 291 } 292 293 /** 294 * Divides all elements of this matrix by the given value. 295 * 296 * @param value The value to divide by. 297 * @return The resultant matrix. 298 */ 299 public Matrix<R, C> div(int value) { 300 return new Matrix<>(this.m_storage.divide(value)); 301 } 302 303 /** 304 * Divides all elements of this matrix by the given value. 305 * 306 * @param value The value to divide by. 307 * @return The resultant matrix. 308 */ 309 public Matrix<R, C> div(double value) { 310 return new Matrix<>(this.m_storage.divide(value)); 311 } 312 313 /** 314 * Calculates the transpose, Mᵀ of this matrix. 315 * 316 * @return The transpose matrix. 317 */ 318 public final Matrix<C, R> transpose() { 319 return new Matrix<>(this.m_storage.transpose()); 320 } 321 322 /** 323 * Returns a copy of this matrix. 324 * 325 * @return A copy of this matrix. 326 */ 327 public final Matrix<R, C> copy() { 328 return new Matrix<>(this.m_storage.copy()); 329 } 330 331 /** 332 * Returns the inverse matrix of "this" matrix. 333 * 334 * @return The inverse of "this" matrix. 335 * @throws org.ejml.data.SingularMatrixException If "this" matrix is non-invertable. 336 */ 337 public final Matrix<R, C> inv() { 338 return new Matrix<>(this.m_storage.invert()); 339 } 340 341 /** 342 * Returns the solution x to the equation Ax = b, where A is "this" matrix. 343 * 344 * <p>The matrix equation could also be written as x = A<sup>-1</sup>b. Where the pseudo inverse 345 * is used if A is not square. 346 * 347 * <p>Note that this method does not support solving using a QR decomposition with full-pivoting, 348 * as only column-pivoting is supported. For full-pivoting, use {@link 349 * #solveFullPivHouseholderQr}. 350 * 351 * @param <C2> Columns in b. 352 * @param b The right-hand side of the equation to solve. 353 * @return The solution to the linear system. 354 */ 355 public final <C2 extends Num> Matrix<C, C2> solve(Matrix<R, C2> b) { 356 return new Matrix<>(this.m_storage.solve(Objects.requireNonNull(b).m_storage)); 357 } 358 359 /** 360 * Solves the least-squares problem Ax=B using a QR decomposition with full pivoting, where this 361 * matrix is A. 362 * 363 * @param <R2> Number of rows in B. 364 * @param <C2> Number of columns in B. 365 * @param other The B matrix. 366 * @return The solution matrix. 367 */ 368 public final <R2 extends Num, C2 extends Num> Matrix<C, C2> solveFullPivHouseholderQr( 369 Matrix<R2, C2> other) { 370 Matrix<C, C2> solution = new Matrix<>(new SimpleMatrix(this.getNumCols(), other.getNumCols())); 371 EigenJNI.solveFullPivHouseholderQr( 372 this.getData(), 373 this.getNumRows(), 374 this.getNumCols(), 375 other.getData(), 376 other.getNumRows(), 377 other.getNumCols(), 378 solution.getData()); 379 return solution; 380 } 381 382 /** 383 * Computes the matrix exponential using Eigen's solver. This method only works for square 384 * matrices, and will otherwise throw an {@link MatrixDimensionException}. 385 * 386 * @return The exponential of A. 387 */ 388 public final Matrix<R, C> exp() { 389 if (this.getNumRows() != this.getNumCols()) { 390 throw new MatrixDimensionException( 391 "Non-square matrices cannot be exponentiated! " 392 + "This matrix is " 393 + this.getNumRows() 394 + " x " 395 + this.getNumCols()); 396 } 397 Matrix<R, C> toReturn = new Matrix<>(new SimpleMatrix(this.getNumRows(), this.getNumCols())); 398 EigenJNI.exp( 399 this.m_storage.getDDRM().getData(), 400 this.getNumRows(), 401 toReturn.m_storage.getDDRM().getData()); 402 return toReturn; 403 } 404 405 /** 406 * Computes the matrix power using Eigen's solver. This method only works for square matrices, and 407 * will otherwise throw an {@link MatrixDimensionException}. 408 * 409 * @param exponent The exponent. 410 * @return The exponential of A. 411 */ 412 public final Matrix<R, C> pow(double exponent) { 413 if (this.getNumRows() != this.getNumCols()) { 414 throw new MatrixDimensionException( 415 "Non-square matrices cannot be raised to a power! " 416 + "This matrix is " 417 + this.getNumRows() 418 + " x " 419 + this.getNumCols()); 420 } 421 Matrix<R, C> toReturn = new Matrix<>(new SimpleMatrix(this.getNumRows(), this.getNumCols())); 422 EigenJNI.pow( 423 this.m_storage.getDDRM().getData(), 424 this.getNumRows(), 425 exponent, 426 toReturn.m_storage.getDDRM().getData()); 427 return toReturn; 428 } 429 430 /** 431 * Returns the determinant of this matrix. 432 * 433 * @return The determinant of this matrix. 434 */ 435 public final double det() { 436 return this.m_storage.determinant(); 437 } 438 439 /** 440 * Computes the Frobenius normal of the matrix. 441 * 442 * <p>normF = Sqrt{ ∑<sub>i=1:m</sub> ∑<sub>j=1:n</sub> { a<sub>ij</sub><sup>2</sup>} } 443 * 444 * @return The matrix's Frobenius normal. 445 */ 446 public final double normF() { 447 return this.m_storage.normF(); 448 } 449 450 /** 451 * Computes the induced p = 1 matrix norm. 452 * 453 * <p>||A||<sub>1</sub>= max(j=1 to n; sum(i=1 to m; |a<sub>ij</sub>|)) 454 * 455 * @return The norm. 456 */ 457 public final double normIndP1() { 458 return NormOps_DDRM.inducedP1(this.m_storage.getDDRM()); 459 } 460 461 /** 462 * Computes the sum of all the elements in the matrix. 463 * 464 * @return Sum of all the elements. 465 */ 466 public final double elementSum() { 467 return this.m_storage.elementSum(); 468 } 469 470 /** 471 * Computes the trace of the matrix. 472 * 473 * @return The trace of the matrix. 474 */ 475 public final double trace() { 476 return this.m_storage.trace(); 477 } 478 479 /** 480 * Returns a matrix which is the result of an element by element power of "this" and b. 481 * 482 * <p>c<sub>i,j</sub> = a<sub>i,j</sub> ^ b 483 * 484 * @param b Scalar. 485 * @return The element by element power of "this" and b. 486 */ 487 public final Matrix<R, C> elementPower(double b) { 488 return new Matrix<>(this.m_storage.elementPower(b)); 489 } 490 491 /** 492 * Returns a matrix which is the result of an element by element power of "this" and b. 493 * 494 * <p>c<sub>i,j</sub> = a<sub>i,j</sub> ^ b 495 * 496 * @param b Scalar. 497 * @return The element by element power of "this" and b. 498 */ 499 public final Matrix<R, C> elementPower(int b) { 500 return new Matrix<>(this.m_storage.elementPower(b)); 501 } 502 503 /** 504 * Extracts a given row into a row vector with new underlying storage. 505 * 506 * @param row The row to extract a vector from. 507 * @return A row vector from the given row. 508 */ 509 public final Matrix<N1, C> extractRowVector(int row) { 510 return new Matrix<>(this.m_storage.extractVector(true, row)); 511 } 512 513 /** 514 * Extracts a given column into a column vector with new underlying storage. 515 * 516 * @param column The column to extract a vector from. 517 * @return A column vector from the given column. 518 */ 519 public final Matrix<R, N1> extractColumnVector(int column) { 520 return new Matrix<>(this.m_storage.extractVector(false, column)); 521 } 522 523 /** 524 * Extracts a matrix of a given size and start position with new underlying storage. 525 * 526 * @param <R2> Number of rows to extract. 527 * @param <C2> Number of columns to extract. 528 * @param height The number of rows of the extracted matrix. 529 * @param width The number of columns of the extracted matrix. 530 * @param startingRow The starting row of the extracted matrix. 531 * @param startingCol The starting column of the extracted matrix. 532 * @return The extracted matrix. 533 */ 534 public final <R2 extends Num, C2 extends Num> Matrix<R2, C2> block( 535 Nat<R2> height, Nat<C2> width, int startingRow, int startingCol) { 536 return new Matrix<>( 537 this.m_storage.extractMatrix( 538 startingRow, 539 startingRow + Objects.requireNonNull(height).getNum(), 540 startingCol, 541 startingCol + Objects.requireNonNull(width).getNum())); 542 } 543 544 /** 545 * Extracts a matrix of a given size and start position with new underlying storage. 546 * 547 * @param <R2> Number of rows to extract. 548 * @param <C2> Number of columns to extract. 549 * @param height The number of rows of the extracted matrix. 550 * @param width The number of columns of the extracted matrix. 551 * @param startingRow The starting row of the extracted matrix. 552 * @param startingCol The starting column of the extracted matrix. 553 * @return The extracted matrix. 554 */ 555 public final <R2 extends Num, C2 extends Num> Matrix<R2, C2> block( 556 int height, int width, int startingRow, int startingCol) { 557 return new Matrix<>( 558 this.m_storage.extractMatrix( 559 startingRow, startingRow + height, startingCol, startingCol + width)); 560 } 561 562 /** 563 * Assign a matrix of a given size and start position. 564 * 565 * @param <R2> Rows in block assignment. 566 * @param <C2> Columns in block assignment. 567 * @param startingRow The row to start at. 568 * @param startingCol The column to start at. 569 * @param other The matrix to assign the block to. 570 */ 571 public <R2 extends Num, C2 extends Num> void assignBlock( 572 int startingRow, int startingCol, Matrix<R2, C2> other) { 573 this.m_storage.insertIntoThis( 574 startingRow, startingCol, Objects.requireNonNull(other).m_storage); 575 } 576 577 /** 578 * Extracts a submatrix from the supplied matrix and inserts it in a submatrix in "this". The 579 * shape of "this" is used to determine the size of the matrix extracted. 580 * 581 * @param <R2> Number of rows to extract. 582 * @param <C2> Number of columns to extract. 583 * @param startingRow The starting row in the supplied matrix to extract the submatrix. 584 * @param startingCol The starting column in the supplied matrix to extract the submatrix. 585 * @param other The matrix to extract the submatrix from. 586 */ 587 public <R2 extends Num, C2 extends Num> void extractFrom( 588 int startingRow, int startingCol, Matrix<R2, C2> other) { 589 CommonOps_DDRM.extract( 590 other.m_storage.getDDRM(), startingRow, startingCol, this.m_storage.getDDRM()); 591 } 592 593 /** 594 * Decompose "this" matrix using Cholesky Decomposition. If the "this" matrix is zeros, it will 595 * return the zero matrix. 596 * 597 * @param lowerTriangular Whether we want to decompose to the lower triangular Cholesky matrix. 598 * @return The decomposed matrix. 599 * @throws RuntimeException if the matrix could not be decomposed(i.e. is not positive 600 * semidefinite). 601 */ 602 public Matrix<R, C> lltDecompose(boolean lowerTriangular) { 603 SimpleMatrix temp = m_storage.copy(); 604 605 CholeskyDecomposition_F64<DMatrixRMaj> chol = 606 DecompositionFactory_DDRM.chol(temp.getNumRows(), lowerTriangular); 607 if (!chol.decompose(temp.getMatrix())) { 608 // check that the input is not all zeros -- if they are, we special case and return all 609 // zeros. 610 var matData = temp.getDDRM().data; 611 var isZeros = true; 612 for (double matDatum : matData) { 613 isZeros &= Math.abs(matDatum) < 1e-6; 614 } 615 if (isZeros) { 616 return new Matrix<>(new SimpleMatrix(temp.getNumRows(), temp.getNumCols())); 617 } 618 619 throw new RuntimeException("Cholesky decomposition failed! Input matrix:\n" + m_storage); 620 } 621 622 return new Matrix<>(SimpleMatrix.wrap(chol.getT(null))); 623 } 624 625 /** 626 * Returns the row major data of this matrix as a double array. 627 * 628 * @return The row major data of this matrix as a double array. 629 */ 630 public double[] getData() { 631 return m_storage.getDDRM().getData(); 632 } 633 634 /** 635 * Creates the identity matrix of the given dimension. 636 * 637 * @param dim The dimension of the desired matrix as a {@link Nat}. 638 * @param <D> The dimension of the desired matrix as a generic. 639 * @return The DxD identity matrix. 640 */ 641 public static <D extends Num> Matrix<D, D> eye(Nat<D> dim) { 642 return new Matrix<>(SimpleMatrix.identity(Objects.requireNonNull(dim).getNum())); 643 } 644 645 /** 646 * Creates the identity matrix of the given dimension. 647 * 648 * @param dim The dimension of the desired matrix as a {@link Num}. 649 * @param <D> The dimension of the desired matrix as a generic. 650 * @return The DxD identity matrix. 651 */ 652 public static <D extends Num> Matrix<D, D> eye(D dim) { 653 return new Matrix<>(SimpleMatrix.identity(Objects.requireNonNull(dim).getNum())); 654 } 655 656 /** 657 * Reassigns dimensions of a {@link Matrix} to allow for operations with other matrices that have 658 * wildcard dimensions. 659 * 660 * @param <R1> Row dimension to assign. 661 * @param <C1> Column dimension to assign. 662 * @param mat The {@link Matrix} to remove the dimensions from. 663 * @return The matrix with reassigned dimensions. 664 */ 665 public static <R1 extends Num, C1 extends Num> Matrix<R1, C1> changeBoundsUnchecked( 666 Matrix<?, ?> mat) { 667 return new Matrix<>(mat.m_storage); 668 } 669 670 /** 671 * Checks if another {@link Matrix} is identical to "this" one within a specified tolerance. 672 * 673 * <p>This will check if each element is in tolerance of the corresponding element from the other 674 * {@link Matrix} or if the elements have the same symbolic meaning. For two elements to have the 675 * same symbolic meaning they both must be either Double.NaN, Double.POSITIVE_INFINITY, or 676 * Double.NEGATIVE_INFINITY. 677 * 678 * <p>NOTE:It is recommended to use {@link Matrix#isEqual(Matrix, double)} over this method when 679 * checking if two matrices are equal as {@link Matrix#isEqual(Matrix, double)} will return false 680 * if an element is uncountable. This method should only be used when uncountable elements need to 681 * be compared. 682 * 683 * @param other The {@link Matrix} to check against this one. 684 * @param tolerance The tolerance to check equality with. 685 * @return true if this matrix is identical to the one supplied. 686 */ 687 public boolean isIdentical(Matrix<?, ?> other, double tolerance) { 688 return MatrixFeatures_DDRM.isIdentical( 689 this.m_storage.getDDRM(), other.m_storage.getDDRM(), tolerance); 690 } 691 692 /** 693 * Checks if another {@link Matrix} is equal to "this" within a specified tolerance. 694 * 695 * <p>This will check if each element is in tolerance of the corresponding element from the other 696 * {@link Matrix}. 697 * 698 * <p>tol ≥ |a<sub>ij</sub> - b<sub>ij</sub>| 699 * 700 * @param other The {@link Matrix} to check against this one. 701 * @param tolerance The tolerance to check equality with. 702 * @return true if this matrix is equal to the one supplied. 703 */ 704 public boolean isEqual(Matrix<?, ?> other, double tolerance) { 705 return MatrixFeatures_DDRM.isEquals( 706 this.m_storage.getDDRM(), other.m_storage.getDDRM(), tolerance); 707 } 708 709 /** 710 * Performs an inplace Cholesky rank update (or downdate). 711 * 712 * <p>If this matrix contains L where A = LLᵀ before the update, it will contain L where LLᵀ = A + 713 * σvvᵀ after the update. 714 * 715 * @param v Vector to use for the update. 716 * @param sigma Sigma to use for the update. 717 * @param lowerTriangular Whether this matrix is lower triangular. 718 */ 719 public void rankUpdate(Matrix<R, N1> v, double sigma, boolean lowerTriangular) { 720 EigenJNI.rankUpdate(this.getData(), this.getNumRows(), v.getData(), sigma, lowerTriangular); 721 } 722 723 @Override 724 public String toString() { 725 return m_storage.toString(); 726 } 727 728 /** 729 * Checks if an object is equal to this {@link Matrix}. 730 * 731 * <p>a<sub>ij</sub> == b<sub>ij</sub> 732 * 733 * @param other The Object to check against this {@link Matrix}. 734 * @return true if the object supplied is a {@link Matrix} and is equal to this matrix. 735 */ 736 @Override 737 public boolean equals(Object other) { 738 return this == other 739 || other instanceof Matrix<?, ?> matrix 740 && !MatrixFeatures_DDRM.hasUncountable(matrix.m_storage.getDDRM()) 741 && MatrixFeatures_DDRM.isEquals(this.m_storage.getDDRM(), matrix.m_storage.getDDRM()); 742 } 743 744 @Override 745 public int hashCode() { 746 return Objects.hash(m_storage); 747 } 748 749 /** 750 * Creates an implementation of the {@link Protobuf} interface for matrices. 751 * 752 * @param <R> The number of rows of the matrices this serializer processes. 753 * @param <C> The number of cols of the matrices this serializer processes. 754 * @param rows The number of rows of the matrices this serializer processes. 755 * @param cols The number of cols of the matrices this serializer processes. 756 * @return The protobuf implementation. 757 */ 758 public static <R extends Num, C extends Num> MatrixProto<R, C> getProto( 759 Nat<R> rows, Nat<C> cols) { 760 return new MatrixProto<>(rows, cols); 761 } 762 763 /** 764 * Creates an implementation of the {@link Struct} interfaces for matrices. 765 * 766 * @param <R> The number of rows of the matrices this serializer processes. 767 * @param <C> The number of cols of the matrices this serializer processes. 768 * @param rows The number of rows of the matrices this serializer processes. 769 * @param cols The number of cols of the matrices this serializer processes. 770 * @return The struct implementation. 771 */ 772 public static <R extends Num, C extends Num> MatrixStruct<R, C> getStruct( 773 Nat<R> rows, Nat<C> cols) { 774 return new MatrixStruct<>(rows, cols); 775 } 776}