public virtual DMatrixRMaj getU(DMatrixRMaj U, bool transpose, bool compact) { U = BidiagonalDecompositionRow_DDRM.handleU(U, false, compact, m, n, min); if (compact) { // U = Q*U1 DMatrixRMaj Q1 = decompQRP.getQ(null, true); DMatrixRMaj U1 = decompBi.getU(null, false, true); CommonOps_DDRM.mult(Q1, U1, U); } else { // U = [Q1*U1 Q2] DMatrixRMaj Q = decompQRP.getQ(U, false); DMatrixRMaj U1 = decompBi.getU(null, false, true); DMatrixRMaj Q1 = CommonOps_DDRM.extract(Q, 0, Q.numRows, 0, min); DMatrixRMaj tmp = new DMatrixRMaj(Q1.numRows, U1.numCols); CommonOps_DDRM.mult(Q1, U1, tmp); CommonOps_DDRM.insert(tmp, Q, 0, 0); } if (transpose) { CommonOps_DDRM.transpose(U); } return(U); }
public virtual DMatrixRMaj getV(DMatrixRMaj V, bool transpose) { if (!prefComputeV) { throw new ArgumentException("As requested V was not computed."); } if (transpose) { if (V == null) { return(Vt); } V.set(Vt); } else { if (V == null) { V = new DMatrixRMaj(Vt.numCols, Vt.numRows); } else { V.reshape(Vt.numCols, Vt.numRows); } CommonOps_DDRM.transpose(Vt, V); } return(V); }
public virtual DMatrixRMaj getU(DMatrixRMaj U, bool transpose) { if (!prefComputeU) { throw new ArgumentException("As requested U was not computed."); } if (transpose) { if (U == null) { return(Ut); } U.set(Ut); } else { if (U == null) { U = new DMatrixRMaj(Ut.numCols, Ut.numRows); } else { U.reshape(Ut.numCols, Ut.numRows); } CommonOps_DDRM.transpose(Ut, U); } return(U); }
//@Override public void update(DMatrixRMaj z, DMatrixRMaj R) { // y = z - H x CommonOps_DDRM.mult(H, x, y); CommonOps_DDRM.subtract(z, y, y); // S = H P H' + R CommonOps_DDRM.mult(H, P, c); CommonOps_DDRM.multTransB(c, H, S); CommonOps_DDRM.addEquals(S, R); // K = PH'S^(-1) if (!solver.setA(S)) { throw new InvalidOperationException("Invert failed"); } solver.invert(S_inv); CommonOps_DDRM.multTransA(H, S_inv, d); CommonOps_DDRM.mult(P, d, K); // x = x + Ky CommonOps_DDRM.mult(K, y, a); CommonOps_DDRM.addEquals(x, a); // P = (I-kH)P = P - (KH)P = P-K(HP) CommonOps_DDRM.mult(H, P, c); CommonOps_DDRM.mult(K, c, b); CommonOps_DDRM.subtractEquals(P, b); }
/** * <p> * Performs a matrix inversion operation that does not modify the original * and stores the results in another matrix. The two matrices must have the * same dimension.<br> * <br> * B = A<sup>-1</sup> * </p> * * <p> * If the algorithm could not invert the matrix then false is returned. If it returns true * that just means the algorithm finished. The results could still be bad * because the matrix is singular or nearly singular. * </p> * * <p> * For medium to large matrices there might be a slight performance boost to using * {@link LinearSolverFactory_DSCC} instead. * </p> * * @param A (Input) The matrix that is to be inverted. Not modified. * @param inverse (Output) Where the inverse matrix is stored. Modified. * @return true if it could invert the matrix false if it could not. */ public static bool invert(DMatrixSparseCSC A, DMatrixRMaj inverse) { if (A.numRows != A.numCols) { throw new ArgumentException("A must be a square matrix"); } if (A.numRows != inverse.numRows || A.numCols != inverse.numCols) { throw new ArgumentException("A and inverse must have the same shape."); } LinearSolverSparse <DMatrixSparseCSC, DMatrixRMaj> solver; solver = LinearSolverFactory_DSCC.lu(FillReducing.NONE); // Ensure that the input isn't modified if (solver.modifiesA()) { A = (DMatrixSparseCSC)A.copy(); } DMatrixRMaj I = CommonOps_DDRM.identity(A.numRows); // decompose then solve the matrix if (!solver.setA(A)) { return(false); } solver.solve(I, inverse); return(true); }
/** * <p> * To decompose the matrix 'A' it must have full rank. 'A' is a 'm' by 'n' matrix. * It requires about 2n*m<sup>2</sup>-2m<sup>2</sup>/3 flops. * </p> * * <p> * The matrix provided here can be of different * dimension than the one specified in the constructor. It just has to be smaller than or equal * to it. * </p> */ public override bool decompose(DMatrixRMaj A) { setExpectedMaxSize(A.numRows, A.numCols); convertToColumnMajor(A); maxAbs = CommonOps_DDRM.elementMaxAbs(A); // initialize pivot variables setupPivotInfo(); // go through each column and perform the decomposition for (int j = 0; j < minLength; j++) { if (j > 0) { updateNorms(j); } swapColumns(j); // if its degenerate stop processing if (!householderPivot(j)) { break; } updateA(j); rank = j + 1; } return(true); }
/** * Returns the Q matrix. */ public DMatrixRMaj getQ() { DMatrixRMaj Q = CommonOps_DDRM.identity(QR.numRows); DMatrixRMaj Q_k = new DMatrixRMaj(QR.numRows, QR.numRows); DMatrixRMaj u = new DMatrixRMaj(QR.numRows, 1); DMatrixRMaj temp = new DMatrixRMaj(QR.numRows, QR.numRows); int N = Math.Min(QR.numCols, QR.numRows); // compute Q by first extracting the householder vectors from the columns of QR and then applying it to Q for (int j = N - 1; j >= 0; j--) { CommonOps_DDRM.extract(QR, j, QR.numRows, j, j + 1, u, j, 0); u.set(j, 1.0); // A = (I - γ*u*u<sup>T</sup>)*A<br> CommonOps_DDRM.setIdentity(Q_k); CommonOps_DDRM.multAddTransB(-gammas[j], u, u, Q_k); CommonOps_DDRM.mult(Q_k, Q, temp); Q.set(temp); } return(Q); }
/** * <p> * Returns true if the matrix is symmetric within the tolerance. Only square matrices can be * symmetric. * </p> * <p> * A matrix is symmetric if:<br> * |a<sub>ij</sub> - a<sub>ji</sub>| ≤ tol * </p> * * @param m A matrix. Not modified. * @param tol Tolerance for how similar two elements need to be. * @return true if it is symmetric and false if it is not. */ public static bool isSymmetric(DMatrixRMaj m, double tol) { if (m.numCols != m.numRows) { return(false); } double max = CommonOps_DDRM.elementMaxAbs(m); for (int i = 0; i < m.numRows; i++) { for (int j = 0; j < i; j++) { double a = m.get(i, j) / max; double b = m.get(j, i) / max; double diff = Math.Abs(a - b); if (!(diff <= tol)) { return(false); } } } return(true); }
/** * <p> * Checks to see if a matrix is orthogonal or isometric. * </p> * * @param Q The matrix being tested. Not modified. * @param tol Tolerance. * @return True if it passes the test. */ public static bool isOrthogonal(DMatrixRMaj Q, double tol) { if (Q.numRows < Q.numCols) { throw new ArgumentException("The number of rows must be more than or equal to the number of columns"); } DMatrixRMaj[] u = CommonOps_DDRM.columnsToVector(Q, null); for (int i = 0; i < u.Count(); i++) { DMatrixRMaj a = u[i]; for (int j = i + 1; j < u.Count(); j++) { double val = VectorVectorMult_DDRM.innerProd(a, u[j]); if (!(Math.Abs(val) <= tol)) { return(false); } } } return(true); }
/** * <p> * Computes a metric which measures the the quality of an eigen value decomposition. If a * value is returned that is close to or smaller than 1e-15 then it is within machine precision. * </p> * <p> * EVD quality is defined as:<br> * <br> * Quality = ||A*V - V*D|| / ||A*V||. * </p> * * @param orig The original matrix. Not modified. * @param eig EVD of the original matrix. Not modified. * @return The quality of the decomposition. */ public static double quality(DMatrixRMaj orig, EigenDecomposition_F64 <DMatrixRMaj> eig) { DMatrixRMaj A = orig; DMatrixRMaj V = EigenOps_DDRM.createMatrixV(eig); DMatrixRMaj D = EigenOps_DDRM.createMatrixD(eig); // L = A*V DMatrixRMaj L = new DMatrixRMaj(A.numRows, V.numCols); CommonOps_DDRM.mult(A, V, L); // R = V*D DMatrixRMaj R = new DMatrixRMaj(V.numRows, D.numCols); CommonOps_DDRM.mult(V, D, R); DMatrixRMaj diff = new DMatrixRMaj(L.numRows, L.numCols); CommonOps_DDRM.subtract(L, R, diff); double top = NormOps_DDRM.normF(diff); double bottom = NormOps_DDRM.normF(L); double error = top / bottom; return(error); }
/** * <p> * Creates a matrix where all but the diagonal elements are zero. The values * of the diagonal elements are specified by the parameter 'vals'. * </p> * * <p> * To extract the diagonal elements from a matrix see {@link #diag()}. * </p> * * @see CommonOps_DDRM#diag(double...) * * @param vals The values of the diagonal elements. * @return A diagonal matrix. */ public static SimpleMatrixD diag(double[] vals) { DMatrixRMaj m = CommonOps_DDRM.diag(vals); SimpleMatrixD ret = wrap(m); return(ret); }
/** * <p> * Creates a pivot matrix that exchanges the rows in a matrix: * <br> * A' = P*A<br> * </p> * <p> * For example, if element 0 in 'pivots' is 2 then the first row in A' will be the 3rd row in A. * </p> * * @param ret If null then a new matrix is declared otherwise the results are written to it. Is modified. * @param pivots Specifies the new order of rows in a matrix. * @param numPivots How many elements in pivots are being used. * @param transposed If the transpose of the matrix is returned. * @return A pivot matrix. */ public static DMatrixRMaj pivotMatrix(DMatrixRMaj ret, int[] pivots, int numPivots, bool transposed) { if (ret == null) { ret = new DMatrixRMaj(numPivots, numPivots); } else { if (ret.numCols != numPivots || ret.numRows != numPivots) { throw new ArgumentException("Unexpected matrix dimension"); } CommonOps_DDRM.fill(ret, 0); } if (transposed) { for (int i = 0; i < numPivots; i++) { ret.set(pivots[i], i, 1); } } else { for (int i = 0; i < numPivots; i++) { ret.set(i, pivots[i], 1); } } return(ret); }
private bool extractSeparate(int numCols) { if (!computeEigenValues()) { return(false); } // ---- set up the helper to decompose the same tridiagonal matrix // swap arrays instead of copying them to make it slightly faster helper.reset(numCols); diagSaved = helper.swapDiag(diagSaved); offSaved = helper.swapOff(offSaved); // extract the orthogonal from the similar transform V = decomp.getQ(V, true); // tell eigenvector algorithm to update this matrix as it computes the rotators vector.setQ(V); // extract eigenvectors if (!vector.process(-1, null, null, values)) { return(false); } // the ordering of the eigenvalues might have changed values = helper.copyEigenvalues(values); // the V matrix contains the eigenvectors. Convert those into column vectors eigenvectors = CommonOps_DDRM.rowsToVector(V, eigenvectors); return(true); }
/** * Computes the d and H parameters. Where d is the average error gradient and * H is an approximation of the hessian. */ private void computeDandH(DMatrixRMaj param, DMatrixRMaj x, DMatrixRMaj y) { func.compute(param, x, tempDH); CommonOps_DDRM.subtractEquals(tempDH, y); computeNumericalJacobian(param, x, jacobian); int numParam = param.getNumElements(); int length = x.getNumElements(); // d = average{ (f(x_i;p) - y_i) * jacobian(:,i) } for (int i = 0; i < numParam; i++) { double total = 0; for (int j = 0; j < length; j++) { total += tempDH.get(j, 0) * jacobian.get(i, j); } d.set(i, 0, total / length); } // compute the approximation of the hessian CommonOps_DDRM.multTransB(jacobian, jacobian, H); CommonOps_DDRM.scale(1.0 / length, H); }
/** * Creates a new identity matrix with the specified size. * * @see CommonOps_DDRM#identity(int) * * @param width The width and height of the matrix. * @return An identity matrix. */ public static SimpleMatrixD identity(int width) { SimpleMatrixD ret = new SimpleMatrixD(width, width); CommonOps_DDRM.setIdentity(ret.mat); return(ret); }
/** * Returns the orthogonal U matrix. * * @param U If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public virtual DMatrixRMaj getU(DMatrixRMaj U, bool transpose, bool compact) { U = handleU(U, transpose, compact, m, n, min); CommonOps_DDRM.setIdentity(U); for (int i = 0; i < m; i++) { u[i] = 0; } for (int j = min - 1; j >= 0; j--) { u[j] = 1; for (int i = j + 1; i < m; i++) { u[i] = UBV.get(i, j); } if (transpose) { QrHelperFunctions_DDRM.rank1UpdateMultL(U, u, gammasU[j], j, j, m); } else { QrHelperFunctions_DDRM.rank1UpdateMultR(U, u, gammasU[j], j, j, m, this.b); } } return(U); }
/** * Returns the orthogonal V matrix. * * @param V If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public virtual DMatrixRMaj getV(DMatrixRMaj V, bool transpose, bool compact) { V = handleV(V, transpose, compact, m, n, min); CommonOps_DDRM.setIdentity(V); // UBV.print(); // todo the very first multiplication can be avoided by setting to the rank1update output for (int j = min - 1; j >= 0; j--) { u[j + 1] = 1; for (int i = j + 2; i < n; i++) { u[i] = UBV.get(j, i); } if (transpose) { QrHelperFunctions_DDRM.rank1UpdateMultL(V, u, gammasV[j], j + 1, j + 1, n); } else { QrHelperFunctions_DDRM.rank1UpdateMultR(V, u, gammasV[j], j + 1, j + 1, n, this.b); } } return(V); }
public void run() { DMatrixRMaj priorX = new DMatrixRMaj(9, 1, true, 0.5, -0.2, 0, 0, 0.2, -0.9, 0, 0.2, -0.5); DMatrixRMaj priorP = CommonOps_DDRM.identity(9); DMatrixRMaj trueX = new DMatrixRMaj(9, 1, true, 0, 0, 0, 0.2, 0.2, 0.2, 0.5, 0.1, 0.6); List <DMatrixRMaj> meas = createSimulatedMeas(trueX); DMatrixRMaj F = createF(T); DMatrixRMaj Q = createQ(T, 0.1); DMatrixRMaj H = createH(); foreach (KalmanFilter f in filters) { long timeBefore = DateTimeHelper.CurrentTimeMilliseconds; f.configure(F, Q, H); for (int trial = 0; trial < NUM_TRIALS; trial++) { f.setState(priorX, priorP); processMeas(f, meas); } long timeAfter = DateTimeHelper.CurrentTimeMilliseconds; Console.WriteLine("Filter = " + f.GetType().Name); Console.WriteLine("Elapsed time: " + (timeAfter - timeBefore)); //System.gc(); GC.Collect(); GC.WaitForPendingFinalizers(); } }
public virtual DMatrixRBlock getT(DMatrixRBlock T) { if (T == null) { T = new DMatrixRBlock(A.numRows, A.numCols, A.blockLength); } else { if (T.numRows != A.numRows || T.numCols != A.numCols) { throw new ArgumentException("T must have the same dimensions as the input matrix"); } CommonOps_DDRM.fill(T, 0); } T.set(0, 0, A.data[0]); for (int i = 1; i < A.numRows; i++) { double d = A.get(i - 1, i); T.set(i, i, A.get(i, i)); T.set(i - 1, i, d); T.set(i, i - 1, d); } return(T); }
/** * <p> * Computes W from the householder reflectors stored in the columns of the row block * submatrix Y. * </p> * * <p> * Y = v<sup>(1)</sup><br> * W = -β<sub>1</sub>v<sup>(1)</sup><br> * for j=2:r<br> * z = -β(I +WY<sup>T</sup>)v<sup>(j)</sup> <br> * W = [W z]<br> * Y = [Y v<sup>(j)</sup>]<br> * end<br> * <br> * where v<sup>(.)</sup> are the house holder vectors, and r is the block length. Note that * Y already contains the householder vectors so it does not need to be modified. * </p> * * <p> * Y and W are assumed to have the same number of rows and columns. * </p> */ public static void computeW_row(int blockLength, DSubmatrixD1 Y, DSubmatrixD1 W, double[] beta, int betaIndex) { int heightY = Y.row1 - Y.row0; CommonOps_DDRM.fill(W.original, 0); // W = -beta*v(1) BlockHouseHolder_DDRB.scale_row(blockLength, Y, W, 0, 1, -beta[betaIndex++]); int min = Math.Min(heightY, W.col1 - W.col0); // set up rest of the rows for (int i = 1; i < min; i++) { // w=-beta*(I + W*Y^T)*u double b = -beta[betaIndex++]; // w = w -beta*W*(Y^T*u) for (int j = 0; j < i; j++) { double yv = BlockHouseHolder_DDRB.innerProdRow(blockLength, Y, i, Y, j, 1); VectorOps_DDRB.add_row(blockLength, W, i, 1, W, j, b * yv, W, i, 1, Y.col1 - Y.col0); } //w=w -beta*u + stuff above BlockHouseHolder_DDRB.add_row(blockLength, Y, i, b, W, i, 1, W, i, 1, Y.col1 - Y.col0); } }
/** * <p> * Element wise p-norm:<br> * <br> * norm = {∑<sub>i=1:m</sub> ∑<sub>j=1:n</sub> { |a<sub>ij</sub>|<sup>p</sup>}}<sup>1/p</sup> * </p> * * <p> * This is not the same as the induced p-norm used on matrices, but is the same as the vector p-norm. * </p> * * @param A Matrix. Not modified. * @param p p value. * @return The norm's value. */ public static double elementP(DMatrix1Row A, double p) { if (p == 1) { return(CommonOps_DDRM.elementSumAbs(A)); } if (p == 2) { return(normF(A)); } else { double max = CommonOps_DDRM.elementMaxAbs(A); if (max == 0.0) { return(0.0); } double total = 0; int size = A.getNumElements(); for (int i = 0; i < size; i++) { double a = A.get(i) / max; total += Math.Pow(Math.Abs(a), p); } return(max * Math.Pow(total, 1.0 / p)); } }
public virtual DMatrixRMaj getT(DMatrixRMaj T) { int N = Ablock.numRows; if (T == null) { T = new DMatrixRMaj(N, N); } else { CommonOps_DDRM.fill(T, 0); } double[] diag = new double[N]; double[] off = new double[N]; ((TridiagonalDecompositionHouseholder_DDRB)alg).getDiagonal(diag, off); T.unsafe_set(0, 0, diag[0]); for (int i = 1; i < N; i++) { T.unsafe_set(i, i, diag[i]); T.unsafe_set(i, i - 1, off[i - 1]); T.unsafe_set(i - 1, i, off[i - 1]); } return(T); }
/** * <p> * The condition number of a matrix is used to measure the sensitivity of the linear * system <b>Ax=b</b>. A value near one indicates that it is a well conditioned matrix.<br> * <br> * κ<sub>p</sub> = ||A||<sub>p</sub>||A<sup>-1</sup>||<sub>p</sub> * </p> * <p> * If the matrix is not square then the condition of either A<sup>T</sup>A or AA<sup>T</sup> is computed. * <p> * @param A The matrix. * @param p p-norm * @return The condition number. */ public static double conditionP(DMatrixRMaj A, double p) { if (p == 2) { return(conditionP2(A)); } else if (A.numRows == A.numCols) { // square matrices are the typical case DMatrixRMaj A_inv = new DMatrixRMaj(A.numRows, A.numCols); if (!CommonOps_DDRM.invert(A, A_inv)) { throw new ArgumentException("A can't be inverted."); } return(normP(A, p) * normP(A_inv, p)); } else { DMatrixRMaj pinv = new DMatrixRMaj(A.numCols, A.numRows); CommonOps_DDRM.pinv(A, pinv); return(normP(A, p) * normP(pinv, p)); } }
//@Override public DMatrixRMaj getQ(DMatrixRMaj Q, bool compact) { int minLength = Math.Min(Ablock.numRows, Ablock.numCols); if (Q == null) { if (compact) { Q = new DMatrixRMaj(Ablock.numRows, minLength); CommonOps_DDRM.setIdentity(Q); } else { Q = new DMatrixRMaj(Ablock.numRows, Ablock.numRows); CommonOps_DDRM.setIdentity(Q); } } DMatrixRBlock Qblock = new DMatrixRBlock(); Qblock.numRows = Q.numRows; Qblock.numCols = Q.numCols; Qblock.blockLength = blockLength; Qblock.data = Q.data; ((QRDecompositionHouseholder_DDRB)alg).getQ(Qblock, compact); convertBlockToRow(Q.numRows, Q.numCols, Ablock.blockLength, Q.data); return(Q); }
public virtual bool setA(DMatrixRMaj A) { pinv.reshape(A.numCols, A.numRows, false); if (!svd.decompose(A)) { return(false); } svd.getU(U_t, true); svd.getV(V, false); double[] S = svd.getSingularValues(); int N = Math.Min(A.numRows, A.numCols); // compute the threshold for singular values which are to be zeroed double maxSingular = 0; for (int i = 0; i < N; i++) { if (S[i] > maxSingular) { maxSingular = S[i]; } } double tau = threshold * Math.Max(A.numCols, A.numRows) * maxSingular; // computer the pseudo inverse of A if (maxSingular != 0.0) { for (int i = 0; i < N; i++) { double s = S[i]; if (s < tau) { S[i] = 0; } else { S[i] = 1.0 / S[i]; } } } // V*W for (int i = 0; i < V.numRows; i++) { int index = i * V.numCols; for (int j = 0; j < V.numCols; j++) { V.data[index++] *= S[j]; } } // V*W*U^T CommonOps_DDRM.mult(V, U_t, pinv); return(true); }
/// <summary> /// Computes the Moore-Penrose pseudo-inverse. /// </summary> public override SimpleMatrixD pseudoInverse() { SimpleMatrixD ret = createMatrix(mat.getNumCols(), mat.getNumRows()); CommonOps_DDRM.pinv(mat, ret.getMatrix()); return(ret); }
/// <summary> /// Returns the result of dividing each element by 'val': /// <code>b[i,j] = a[i,j]/val</code> /// </summary> /// <param name="val">Divisor</param> /// <returns>Matrix with its elements divided by the specified value.</returns> /// <see cref="CommonOps_DDRM.divide(DMatrixD1, double)"/> public override SimpleMatrixD divide(double val) { SimpleMatrixD ret = copy(); var rm = ret.getMatrix(); CommonOps_DDRM.divide(rm, val); return(ret); }
/** * Makes a draw on the distribution. The results are added to parameter 'x' */ public void next(DMatrixRMaj x) { for (int i = 0; i < r.numRows; i++) { r.set(i, 0, (double)rand.NextGaussian()); } CommonOps_DDRM.multAdd(A, r, x); }
public virtual void minus(DMatrixRMaj A, /**/ double b, DMatrixRMaj output) { CommonOps_DDRM.subtract(A, (double)b, output); } public virtual void plus(DMatrixRMaj A, /**/ double b, DMatrixRMaj output) { CommonOps_DDRM.add(A, (double)b, output); }
/// <summary> /// Returns the result of scaling each element by 'val': /// <code>b[i,j] = val*a[i,j]</code> /// </summary> /// <param name="val">The multiplication factor.</param> /// <see cref="CommonOps_DDRM.scale(double, DMatrixRMaj)"/> public override SimpleMatrixD scale(double val) { SimpleMatrixD ret = copy(); var rm = ret.getMatrix(); CommonOps_DDRM.scale(val, rm); return(ret); }