/** * Performs sanity checks on the input data and reshapes internal matrices. By reshaping * a matrix it will only declare new memory when needed. */ public void configure(DMatrixRMaj initParam, DMatrixRMaj X, DMatrixRMaj Y) { if (Y.getNumRows() != X.getNumRows()) { throw new ArgumentException("Different vector lengths"); } else if (Y.getNumCols() != 1 || X.getNumCols() != 1) { throw new ArgumentException("Inputs must be a column vector"); } int numParam = initParam.getNumElements(); int numPoints = Y.getNumRows(); if (param.getNumElements() != initParam.getNumElements()) { // reshaping a matrix means that new memory is only declared when needed this.param.reshape(numParam, 1, false); this.d.reshape(numParam, 1, false); this.H.reshape(numParam, numParam, false); this.negDelta.reshape(numParam, 1, false); this.tempParam.reshape(numParam, 1, false); this.A.reshape(numParam, numParam, false); } param.set(initParam); // reshaping a matrix means that new memory is only declared when needed temp0.reshape(numPoints, 1, false); temp1.reshape(numPoints, 1, false); tempDH.reshape(numPoints, 1, false); jacobian.reshape(numParam, numPoints, false); }
/** * 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); }
public static void inv(DMatrixRMaj mat, DMatrixRMaj inv) { double max = Math.Abs(mat.data[0]); int N = mat.getNumElements(); for (int i = 1; i < N; i++) { double a = Math.Abs(mat.data[i]); if (a > max) { max = a; } } switch (mat.numRows) { case 2: inv2(mat, inv, 1.0 / max); break; case 3: inv3(mat, inv, 1.0 / max); break; case 4: inv4(mat, inv, 1.0 / max); break; case 5: inv5(mat, inv, 1.0 / max); break; default: throw new ArgumentException("Not supported"); } }
public static void convert(DMatrixRMaj src, FMatrixRMaj dst) { int N = src.getNumElements(); for (int i = 0; i < N; i++) { dst.data[i] = (float)src.data[i]; } }
/** * <p> * Adds random values to each element in the matrix from an uniform distribution.<br> * <br> * a<sub>ij</sub> = a<sub>ij</sub> + U(min,max)<br> * </p> * * @param A The matrix who is to be randomized. Modified * @param min The minimum value each element can be. * @param max The maximum value each element can be.. * @param rand Random number generator used to fill the matrix. */ public static void addUniform(DMatrixRMaj A, double min, double max, IMersenneTwister rand) { double[] d = A.getData(); int size = A.getNumElements(); double r = max - min; for (int i = 0; i < size; i++) { d[i] += r * rand.NextDouble() + min; } }
/** * <p> * Creates a reflector from the provided vector and gamma.<br> * <br> * Q = I - γ u u<sup>T</sup><br> * </p> * * <p> * In practice {@link VectorVectorMult_DDRM#householder(double, DMatrixD1, DMatrixD1, DMatrixD1)} multHouseholder} * should be used for performance reasons since there is no need to calculate Q explicitly. * </p> * * @param u A vector. Not modified. * @param gamma To produce a reflector gamma needs to be equal to 2/||u||. * @return An orthogonal reflector. */ public static DMatrixRMaj createReflector(DMatrixRMaj u, double gamma) { if (!MatrixFeatures_DDRM.isVector(u)) { throw new ArgumentException("u must be a vector"); } DMatrixRMaj Q = CommonOps_DDRM.identity(u.getNumElements()); CommonOps_DDRM.multAddTransB(-gamma, u, u, Q); return(Q); }
/** * Computes the QR decomposition of the provided matrix. * * @param A Matrix which is to be decomposed. Not modified. */ public void decompose(DMatrixRMaj A) { Equation.Equation eq = new Equation.Equation(); this.QR = (DMatrixRMaj)A.copy(); int N = Math.Min(A.numCols, A.numRows); gammas = new double[A.numCols]; for (int i = 0; i < N; i++) { // update temporary variables eq.alias(QR.numRows - i, "Ni", QR, "QR", i, "i"); // Place the column that should be zeroed into v eq.process("v=QR(i:,i)"); eq.process("maxV=max(abs(v))"); // Note that v is lazily created above. Need direct access to it, which is done below. DMatrixRMaj v = eq.lookupMatrix("v"); double maxV = eq.lookupDouble("maxV"); if (maxV > 0 && v.getNumElements() > 1) { // normalize to reduce overflow issues eq.process("v=v/maxV"); // compute the magnitude of the vector double tau = NormOps_DDRM.normF(v); if (v.get(0) < 0) { tau *= -1.0; } eq.alias(tau, "tau"); eq.process("u_0 = v(0,0)+tau"); eq.process("gamma = u_0/tau"); eq.process("v=v/u_0"); eq.process("v(0,0)=1"); eq.process("QR(i:,i:) = (eye(Ni) - gamma*v*v')*QR(i:,i:)"); eq.process("QR(i:,i) = v"); eq.process("QR(i,i) = -1*tau*maxV"); // save gamma for recomputing Q later on gammas[i] = eq.lookupDouble("gamma"); } } }
/** * Normalizes the matrix such that the Frobenius norm is equal to one. * * @param A The matrix that is to be normalized. */ public static void normalizeF(DMatrixRMaj A) { double val = normF(A); if (val == 0) { return; } int size = A.getNumElements(); for (int i = 0; i < size; i++) { A.div(i, val); } }
/** * <p> * Performs a rank one update on matrix A using vectors u and w. The results are stored in A.<br> * <br> * A = A + γ u w<sup>T</sup><br> * </p> * <p> * This is called a rank1 update because the matrix u w<sup>T</sup> has a rank of 1. * </p> * * @param gamma A scalar. * @param A A m by m matrix. Modified. * @param u A vector with m elements. Not modified. */ public static void rank1Update(double gamma, DMatrixRMaj A, DMatrixRMaj u, DMatrixRMaj w) { int n = u.getNumElements(); int matrixIndex = 0; for (int i = 0; i < n; i++) { double elementU = u.data[i]; for (int j = 0; j < n; j++) { A.data[matrixIndex++] += gamma * elementU * w.data[j]; } } }
/** * Computes the QR decomposition of the provided matrix. * * @param A Matrix which is to be decomposed. Not modified. */ public void decompose(DMatrixRMaj A) { this.QR = (DMatrixRMaj)A.copy(); int N = Math.Min(A.numCols, A.numRows); gammas = new double[A.numCols]; DMatrixRMaj A_small = new DMatrixRMaj(A.numRows, A.numCols); DMatrixRMaj A_mod = new DMatrixRMaj(A.numRows, A.numCols); DMatrixRMaj v = new DMatrixRMaj(A.numRows, 1); DMatrixRMaj Q_k = new DMatrixRMaj(A.numRows, A.numRows); for (int i = 0; i < N; i++) { // reshape temporary variables A_small.reshape(QR.numRows - i, QR.numCols - i, false); A_mod.reshape(A_small.numRows, A_small.numCols, false); v.reshape(A_small.numRows, 1, false); Q_k.reshape(v.getNumElements(), v.getNumElements(), false); // use extract matrix to get the column that is to be zeroed CommonOps_DDRM.extract(QR, i, QR.numRows, i, i + 1, v, 0, 0); double max = CommonOps_DDRM.elementMaxAbs(v); if (max > 0 && v.getNumElements() > 1) { // normalize to reduce overflow issues CommonOps_DDRM.divide(v, max); // compute the magnitude of the vector double tau = NormOps_DDRM.normF(v); if (v.get(0) < 0) { tau *= -1.0; } double u_0 = v.get(0) + tau; double gamma = u_0 / tau; CommonOps_DDRM.divide(v, u_0); v.set(0, 1.0); // extract the submatrix of A which is being operated on CommonOps_DDRM.extract(QR, i, QR.numRows, i, QR.numCols, A_small, 0, 0); // A = (I - γ*u*u<sup>T</sup>)A CommonOps_DDRM.setIdentity(Q_k); CommonOps_DDRM.multAddTransB(-gamma, v, v, Q_k); CommonOps_DDRM.mult(Q_k, A_small, A_mod); // save the results CommonOps_DDRM.insert(A_mod, QR, i, i); CommonOps_DDRM.insert(v, QR, i, i); QR.unsafe_set(i, i, -tau * max); // save gamma for recomputing Q later on gammas[i] = gamma; } } }