/** * <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> * 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); }
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); }
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); }
/** * An alternative implementation of {@link #multTransA_small} that performs well on large * matrices. There is a relative performance hit when used on small matrices. * * @param A A matrix that is m by n. Not modified. * @param B A Vector that has length m. Not modified. * @param C A column vector that has length n. Modified. */ public static void multTransA_reorder(DMatrix1Row A, DMatrixD1 B, DMatrixD1 C) { if (C.numCols != 1) { throw new MatrixDimensionException("C is not a column vector"); } else if (C.numRows != A.numCols) { throw new MatrixDimensionException("C is not the expected length"); } if (B.numRows == 1) { if (A.numRows != B.numCols) { throw new MatrixDimensionException("A and B are not compatible"); } } else if (B.numCols == 1) { if (A.numRows != B.numRows) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } if (A.numRows == 0) { CommonOps_DDRM.fill(C, 0); return; } double B_val = B.get(0); for (int i = 0; i < A.numCols; i++) { C.set(i, A.get(i) * B_val); } int indexA = A.numCols; for (int i = 1; i < A.numRows; i++) { B_val = B.get(i); for (int j = 0; j < A.numCols; j++) { C.plus(j, A.get(indexA++) * B_val); } } }
/** * <p> * Performs a matrix vector multiply.<br> * <br> * c = A * b <br> * and<br> * c = A * b<sup>T</sup> <br> * <br> * c<sub>i</sub> = Sum{ j=1:n, a<sub>ij</sub> * b<sub>j</sub>}<br> * <br> * where A is a matrix, b is a column or transposed row vector, and c is a column vector. * </p> * * @param A A matrix that is m by n. Not modified. * @param B A vector that has length n. Not modified. * @param C A column vector that has length m. Modified. */ public static void mult(DMatrix1Row A, DMatrixD1 B, DMatrixD1 C) { if (C.numCols != 1) { throw new MatrixDimensionException("C is not a column vector"); } else if (C.numRows != A.numRows) { throw new MatrixDimensionException("C is not the expected length"); } if (B.numRows == 1) { if (A.numCols != B.numCols) { throw new MatrixDimensionException("A and B are not compatible"); } } else if (B.numCols == 1) { if (A.numCols != B.numRows) { throw new MatrixDimensionException("A and B are not compatible"); } } else { throw new MatrixDimensionException("B is not a vector"); } if (A.numCols == 0) { CommonOps_DDRM.fill(C, 0); return; } int indexA = 0; int cIndex = 0; double b0 = B.get(0); for (int i = 0; i < A.numRows; i++) { double total = A.get(indexA++) * b0; for (int j = 1; j < A.numCols; j++) { total += A.get(indexA++) * B.get(j); } C.set(cIndex++, total); } }
/** * @see CommonOps_DDRM#mult(double, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row) */ public static void mult_reorder(double alpha, DMatrix1Row A, DMatrix1Row B, DMatrix1Row C) { UtilEjml.assertTrue(A != C && B != C, "Neither 'A' or 'B' can be the same matrix as 'C'"); UtilEjml.assertShape(A.numCols, B.numRows, "The 'A' and 'B' matrices do not have compatible dimensions"); C.reshape(A.numRows, B.numCols); if (A.numCols == 0 || A.numRows == 0) { CommonOps_DDRM.fill(C, 0); return; } int endOfKLoop = B.numRows * B.numCols; //CONCURRENT_BELOW EjmlConcurrency.loopFor(0, A.numRows, i -> { for (int i = 0; i < A.numRows; i++) { int indexCbase = i * C.numCols; int indexA = i * A.numCols; // need to assign C.data to a value initially int indexB = 0; int indexC = indexCbase; int end = indexB + B.numCols; double valA = alpha * A.data[indexA++]; while (indexB < end) { C.set(indexC++, valA * B.data[indexB++]); } // now add to it while (indexB != endOfKLoop) { // k loop indexC = indexCbase; end = indexB + B.numCols; valA = alpha * A.data[indexA++]; while (indexB < end) { // j loop C.data[indexC++] += valA * B.data[indexB++]; } } } //CONCURRENT_ABOVE }); }
//CONCURRENT_OMIT_END /** * @see CommonOps_DDRM#multTransA(double, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row) */ public static void multTransA_reorder(double alpha, DMatrix1Row A, DMatrix1Row B, DMatrix1Row C) { UtilEjml.assertTrue(A != C && B != C, "Neither 'A' or 'B' can be the same matrix as 'C'"); UtilEjml.assertShape(A.numRows, B.numRows, "The 'A' and 'B' matrices do not have compatible dimensions"); C.reshape(A.numCols, B.numCols); if (A.numCols == 0 || A.numRows == 0) { CommonOps_DDRM.fill(C, 0); return; } //CONCURRENT_BELOW EjmlConcurrency.loopFor(0, A.numRows, i -> { for (int i = 0; i < A.numCols; i++) { int indexC_start = i * C.numCols; // first assign R double valA = alpha * A.data[i]; int indexB = 0; int end = indexB + B.numCols; int indexC = indexC_start; while (indexB < end) { C.set(indexC++, valA * B.data[indexB++]); } // now increment it for (int k = 1; k < A.numRows; k++) { valA = alpha * A.unsafe_get(k, i); end = indexB + B.numCols; indexC = indexC_start; // this is the loop for j while (indexB < end) { C.data[indexC++] += valA * B.data[indexB++]; } } } //CONCURRENT_ABOVE }); }
/** * <p>Sets the value of A to all zeros except along the diagonal.</p> * * @param A Block matrix. */ public static void setIdentity(DMatrixRBlock A) { int minLength = Math.Min(A.numRows, A.numCols); CommonOps_DDRM.fill(A, 0); int blockLength = A.blockLength; for (int i = 0; i < minLength; i += blockLength) { int h = Math.Min(blockLength, A.numRows - i); int w = Math.Min(blockLength, A.numCols - i); int index = i * A.numCols + h * i; int m = Math.Min(h, w); for (int k = 0; k < m; k++) { A.data[index + k * w + k] = 1; } } }
//CONCURRENT_OMIT_BEGIN /** * @see CommonOps_DDRM#multTransAB(double, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row, org.ejml.data.DMatrix1Row) */ public static void multTransAB_aux(double alpha, DMatrix1Row A, DMatrix1Row B, DMatrix1Row C, double[] aux) { UtilEjml.assertTrue(A != C && B != C, "Neither 'A' or 'B' can be the same matrix as 'C'"); UtilEjml.assertShape(A.numRows, B.numCols, "The 'A' and 'B' matrices do not have compatible dimensions"); C.reshape(A.numCols, B.numRows); if (aux == null) { aux = new double[A.numRows]; } if (A.numCols == 0 || A.numRows == 0) { CommonOps_DDRM.fill(C, 0); return; } int indexC = 0; for (int i = 0; i < A.numCols; i++) { for (int k = 0; k < B.numCols; k++) { aux[k] = A.unsafe_get(k, i); } for (int j = 0; j < B.numRows; j++) { double total = 0; for (int k = 0; k < B.numCols; k++) { total += aux[k] * B.unsafe_get(j, k); } C.set(indexC++, alpha * total); } } }
public virtual void divide(DMatrixRMaj A, /**/ double val, DMatrixRMaj output) { CommonOps_DDRM.divide(A, (double)val, output); } public virtual bool invert(DMatrixRMaj A, DMatrixRMaj output) { return(CommonOps_DDRM.invert(A, output)); } public virtual void pseudoInverse(DMatrixRMaj A, DMatrixRMaj output) { CommonOps_DDRM.pinv(A, output); } public virtual bool solve(DMatrixRMaj A, DMatrixRMaj X, DMatrixRMaj B) { return(CommonOps_DDRM.solve(A, B, X)); } public virtual void set(DMatrixRMaj A, /**/ double val) { CommonOps_DDRM.fill(A, (double)val); }
/// <summary> /// Sets all the elements in this matrix equal to the specified value. /// </summary> /// <see cref="CommonOps_DDRM.fill(DMatrixD1, double)"/> public override void set(double val) { CommonOps_DDRM.fill(mat, val); }
/** * <p> * Sets every element in the matrix to the specified value.<br> * <br> * a<sub>ij</sub> = value * <p> * * @param A A matrix whose elements are about to be set. Modified. * @param value The value each element will have. */ public static void set(DMatrixRBlock A, double value) { CommonOps_DDRM.fill(A, value); }
public void fill(Matrix A, double value) { CommonOps_DDRM.fill((DMatrixRMaj)A, (double)value); }
/** * <p> * Given an eigenvalue it computes an eigenvector using inverse iteration: * <br> * for i=1:MAX {<br> * (A - μI)z<sup>(i)</sup> = q<sup>(i-1)</sup><br> * q<sup>(i)</sup> = z<sup>(i)</sup> / ||z<sup>(i)</sup>||<br> * λ<sup>(i)</sup> = q<sup>(i)</sup><sup>T</sup> A q<sup>(i)</sup><br> * }<br> * </p> * <p> * NOTE: If there is another eigenvalue that is very similar to the provided one then there * is a chance of it converging towards that one instead. The larger a matrix is the more * likely this is to happen. * </p> * @param A Matrix whose eigenvector is being computed. Not modified. * @param eigenvalue The eigenvalue in the eigen pair. * @return The eigenvector or null if none could be found. */ public static DEigenpair computeEigenVector(DMatrixRMaj A, double eigenvalue) { if (A.numRows != A.numCols) { throw new ArgumentException("Must be a square matrix."); } DMatrixRMaj M = new DMatrixRMaj(A.numRows, A.numCols); DMatrixRMaj x = new DMatrixRMaj(A.numRows, 1); DMatrixRMaj b = new DMatrixRMaj(A.numRows, 1); CommonOps_DDRM.fill(b, 1); // perturb the eigenvalue slightly so that its not an exact solution the first time // eigenvalue -= eigenvalue*UtilEjml.EPS*10; double origEigenvalue = eigenvalue; SpecializedOps_DDRM.addIdentity(A, M, -eigenvalue); double threshold = NormOps_DDRM.normPInf(A) * UtilEjml.EPS; double prevError = double.MaxValue; bool hasWorked = false; LinearSolverDense <DMatrixRMaj> solver = LinearSolverFactory_DDRM.linear(M.numRows); double perp = 0.0001; for (int i = 0; i < 200; i++) { bool failed = false; // if the matrix is singular then the eigenvalue is within machine precision // of the true value, meaning that x must also be. if (!solver.setA(M)) { failed = true; } else { solver.solve(b, x); } // see if solve silently failed if (MatrixFeatures_DDRM.hasUncountable(x)) { failed = true; } if (failed) { if (!hasWorked) { // if it failed on the first trial try perturbing it some more double val = i % 2 == 0 ? 1.0 - perp : 1.0 + perp; // maybe this should be turn into a parameter allowing the user // to configure the wise of each step eigenvalue = origEigenvalue * Math.Pow(val, i / 2 + 1); SpecializedOps_DDRM.addIdentity(A, M, -eigenvalue); } else { // otherwise assume that it was so accurate that the matrix was singular // and return that result return(new DEigenpair(eigenvalue, b)); } } else { hasWorked = true; b.set(x); NormOps_DDRM.normalizeF(b); // compute the residual CommonOps_DDRM.mult(M, b, x); double error = NormOps_DDRM.normPInf(x); if (error - prevError > UtilEjml.EPS * 10) { // if the error increased it is probably converging towards a different // eigenvalue // CommonOps.set(b,1); prevError = double.MaxValue; hasWorked = false; double val = i % 2 == 0 ? 1.0 - perp : 1.0 + perp; eigenvalue = origEigenvalue * Math.Pow(val, 1); } else { // see if it has converged if (error <= threshold || Math.Abs(prevError - error) <= UtilEjml.EPS) { return(new DEigenpair(eigenvalue, b)); } // update everything prevError = error; eigenvalue = VectorVectorMult_DDRM.innerProdA(b, A, b); } SpecializedOps_DDRM.addIdentity(A, M, -eigenvalue); } } return(null); }