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); }
/** * 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> * 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); }
//@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); }
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); }
//@Override public void predict() { // x = F x CommonOps_DDRM.mult(F, x, a); x.set(a); // P = F P F' + Q CommonOps_DDRM.mult(F, P, b); CommonOps_DDRM.multTransB(b, F, P); CommonOps_DDRM.addEquals(P, Q); }
/** * Compute the A matrix from the Q and R matrices. * * @return The A matrix. */ public override DMatrixRMaj getA() { if (A.data.Length < numRows * numCols) { A = new DMatrixRMaj(numRows, numCols); } A.reshape(numRows, numCols, false); CommonOps_DDRM.mult(Q, R, A); return(A); }
/** * Creates a newJava.Util.Random symmetric matrix that will have the specified real eigenvalues. * * @param num Dimension of the resulting matrix. * @param randJava.Util.Random number generator. * @param eigenvalues Set of real eigenvalues that the matrix will have. * @return AJava.Util.Random matrix with the specified eigenvalues. */ public static DMatrixRMaj symmetricWithEigenvalues(int num, Java.Util.Random rand, double[] eigenvalues) { DMatrixRMaj V = RandomMatrices_DDRM.orthogonal(num, num, rand); DMatrixRMaj D = CommonOps_DDRM.diag(eigenvalues); DMatrixRMaj temp = new DMatrixRMaj(num, num); CommonOps_DDRM.mult(V, D, temp); CommonOps_DDRM.multTransB(temp, V, D); return(D); }
/** * Computes the dot product of each basis vector against the sample. Can be used as a measure * for membership in the training sample set. High values correspond to a better fit. * * @param sample Sample of original data. * @return Higher value indicates it is more likely to be a member of input dataset. */ public double response(double[] sample) { if (sample.Length != A.numCols) { throw new ArgumentException("Expected input vector to be in sample space"); } DMatrixRMaj dots = new DMatrixRMaj(numComponents, 1); DMatrixRMaj s = DMatrixRMaj.wrap(A.numCols, 1, sample); CommonOps_DDRM.mult(V_t, s, dots); return(NormOps_DDRM.normF(dots)); }
public static double quality(DMatrixRMaj orig, DMatrixRMaj U, DMatrixRMaj W, DMatrixRMaj Vt) { // foundA = U*W*Vt DMatrixRMaj UW = new DMatrixRMaj(U.numRows, W.numCols); CommonOps_DDRM.mult(U, W, UW); DMatrixRMaj foundA = new DMatrixRMaj(UW.numRows, Vt.numCols); CommonOps_DDRM.mult(UW, Vt, foundA); double normA = NormOps_DDRM.normF(foundA); return(SpecializedOps_DDRM.diffNormF(orig, foundA) / normA); }
private void checkMatrix(int numRows, int numCols) { DMatrixRMaj A = RandomMatrices_DDRM.rectangle(numRows, numCols, -1, 1, rand); QRExampleOperations alg = new QRExampleOperations(); alg.decompose(A); DMatrixRMaj Q = alg.getQ(); DMatrixRMaj R = alg.getR(); DMatrixRMaj A_found = new DMatrixRMaj(numRows, numCols); CommonOps_DDRM.mult(Q, R, A_found); Assert.IsTrue(MatrixFeatures_DDRM.isIdentical(A, A_found, UtilEjml.TEST_F64)); }
/** * Converts a vector from sample space into eigen space. * * @param sampleData Sample space data. * @return Eigen space projection. */ public double[] sampleToEigenSpace(double[] sampleData) { if (sampleData.Length != A.getNumCols()) { throw new ArgumentException("Unexpected sample length"); } DMatrixRMaj mean = DMatrixRMaj.wrap(A.getNumCols(), 1, this.mean); DMatrixRMaj s = new DMatrixRMaj(A.getNumCols(), 1, true, sampleData); DMatrixRMaj r = new DMatrixRMaj(numComponents, 1); CommonOps_DDRM.subtract(s, mean, s); CommonOps_DDRM.mult(V_t, s, r); return(r.data); }
/** * This method computes the eigen vector with the largest eigen value by using the * direct power method. This technique is the easiest to implement, but the slowest to converge. * Works only if all the eigenvalues are real. * * @param A The matrix. Not modified. * @return If it converged or not. */ public bool computeDirect(DMatrixRMaj A) { initPower(A); bool converged = false; for (int i = 0; i < maxIterations && !converged; i++) { // q0.print(); CommonOps_DDRM.mult(A, q0, q1); double s = NormOps_DDRM.normPInf(q1); CommonOps_DDRM.divide(q1, s, q2); converged = checkConverged(A); } return(converged); }
public bool extractVectors(DMatrixRMaj Q_h) { Array.Clear(eigenvectorTemp.data, 0, eigenvectorTemp.data.Length); // extract eigenvectors from the shur matrix // start at the top left corner of the matrix bool triangular = true; for (int i = 0; i < N; i++) { Complex_F64 c = _implicit.eigenvalues[N - i - 1]; if (triangular && !c.isReal()) { triangular = false; } if (c.isReal() && eigenvectors[N - i - 1] == null) { solveEigenvectorDuplicateEigenvalue(c.real, i, triangular); } } // translate the eigenvectors into the frame of the original matrix if (Q_h != null) { DMatrixRMaj temp = new DMatrixRMaj(N, 1); for (int i = 0; i < N; i++) { DMatrixRMaj v = eigenvectors[i]; if (v != null) { CommonOps_DDRM.mult(Q_h, v, temp); eigenvectors[i] = temp; temp = v; } } } return(true); }
private List <DMatrixRMaj> createSimulatedMeas(DMatrixRMaj x) { List <DMatrixRMaj> ret = new List <DMatrixRMaj>(); DMatrixRMaj F = createF(T); DMatrixRMaj H = createH(); // UtilEjml.print(F); // UtilEjml.print(H); DMatrixRMaj x_next = new DMatrixRMaj(x); DMatrixRMaj z = new DMatrixRMaj(H.numRows, 1); for (int i = 0; i < MAX_STEPS; i++) { CommonOps_DDRM.mult(F, x, x_next); CommonOps_DDRM.mult(H, x_next, z); ret.Add((DMatrixRMaj)z.copy()); x.set(x_next); } return(ret); }
/** * <p> * Creates a random matrix which will have the provided singular values. The length of sv * is assumed to be the rank of the matrix. This can be useful for testing purposes when one * needs to ensure that a matrix is not singular but randomly generated. * </p> * * @param numRows Number of rows in generated matrix. * @param numCols NUmber of columns in generated matrix. * @param rand Random number generator. * @param sv Singular values of the matrix. * @return A new matrix with the specified singular values. */ public static DMatrixRMaj singleValues(int numRows, int numCols, IMersenneTwister rand, double[] sv) { DMatrixRMaj U = RandomMatrices_DDRM.orthogonal(numRows, numRows, rand); DMatrixRMaj V = RandomMatrices_DDRM.orthogonal(numCols, numCols, rand); DMatrixRMaj S = new DMatrixRMaj(numRows, numCols); int min = Math.Min(numRows, numCols); min = Math.Min(min, sv.Length); for (int i = 0; i < min; i++) { S.set(i, i, sv[i]); } DMatrixRMaj tmp = new DMatrixRMaj(numRows, numCols); CommonOps_DDRM.mult(U, S, tmp); CommonOps_DDRM.multTransB(tmp, V, S); return(S); }
/** * <p> * Creates aJava.Util.Random matrix which will have the provided singular values. The Count() of sv * is assumed to be the rank of the matrix. This can be useful for testing purposes when one * needs to ensure that a matrix is not singular but randomly generated. * </p> * * @param numRows Number of rows in generated matrix. * @param numCols NUmber of columns in generated matrix. * @param randJava.Util.Random number generator. * @param sv Singular values of the matrix. * @return A new matrix with the specified singular values. */ public static DMatrixRMaj singular(int numRows, int numCols, Java.Util.Random rand, double[] sv) { DMatrixRMaj U, V, S; // speed it up in compact format if (numRows > numCols) { U = RandomMatrices_DDRM.orthogonal(numRows, numCols, rand); V = RandomMatrices_DDRM.orthogonal(numCols, numCols, rand); S = new DMatrixRMaj(numCols, numCols); } else { U = RandomMatrices_DDRM.orthogonal(numRows, numRows, rand); V = RandomMatrices_DDRM.orthogonal(numCols, numCols, rand); S = new DMatrixRMaj(numRows, numCols); } int min = Math.Min(numRows, numCols); min = Math.Min(min, sv.Count()); for (int i = 0; i < min; i++) { S.set(i, i, sv[i]); } DMatrixRMaj tmp = new DMatrixRMaj(numRows, numCols); CommonOps_DDRM.mult(U, S, tmp); S.reshape(numRows, numCols); CommonOps_DDRM.multTransB(tmp, V, S); return(S); }
public static void main(String[] args) { IMersenneTwister rand = new MersenneTwisterFast(234); // easy to work with sparse format, but hard to do computations with DMatrixSparseTriplet work = new DMatrixSparseTriplet(5, 4, 5); work.addItem(0, 1, 1.2); work.addItem(3, 0, 3); work.addItem(1, 1, 22.21234); work.addItem(2, 3, 6); // convert into a format that's easier to perform math with DMatrixSparseCSC Z = ConvertDMatrixStruct.convert(work, (DMatrixSparseCSC)null); // print the matrix to standard out in two different formats Z.print(); Console.WriteLine(); Z.printNonZero(); Console.WriteLine(); // Create a large matrix that is 5% filled DMatrixSparseCSC A = RandomMatrices_DSCC.rectangle(ROWS, COLS, (int)(ROWS * COLS * 0.05), rand); // large vector that is 70% filled DMatrixSparseCSC x = RandomMatrices_DSCC.rectangle(COLS, XCOLS, (int)(XCOLS * COLS * 0.7), rand); Console.WriteLine("Done generating random matrices"); // storage for the initial solution DMatrixSparseCSC y = new DMatrixSparseCSC(ROWS, XCOLS, 0); DMatrixSparseCSC z = new DMatrixSparseCSC(ROWS, XCOLS, 0); // To demonstration how to perform sparse math let's multiply: // y=A*x // Optional storage is set to null so that it will declare it internally long before = DateTimeHelper.CurrentTimeMilliseconds; IGrowArray workA = new IGrowArray(A.numRows); DGrowArray workB = new DGrowArray(A.numRows); for (int i = 0; i < 100; i++) { CommonOps_DSCC.mult(A, x, y, workA, workB); CommonOps_DSCC.add(1.5, y, 0.75, y, z, workA, workB); } long after = DateTimeHelper.CurrentTimeMilliseconds; Console.WriteLine("norm = " + NormOps_DSCC.fastNormF(y) + " sparse time = " + (after - before) + " ms"); DMatrixRMaj Ad = ConvertDMatrixStruct.convert(A, (DMatrixRMaj)null); DMatrixRMaj xd = ConvertDMatrixStruct.convert(x, (DMatrixRMaj)null); DMatrixRMaj yd = new DMatrixRMaj(y.numRows, y.numCols); DMatrixRMaj zd = new DMatrixRMaj(y.numRows, y.numCols); before = DateTimeHelper.CurrentTimeMilliseconds; for (int i = 0; i < 100; i++) { CommonOps_DDRM.mult(Ad, xd, yd); CommonOps_DDRM.add(1.5, yd, 0.75, yd, zd); } after = DateTimeHelper.CurrentTimeMilliseconds; Console.WriteLine("norm = " + NormOps_DDRM.fastNormF(yd) + " dense time = " + (after - before) + " ms"); }
/** Revises the CMA-ES distribution to reflect the current fitness results in the provided subpopulation. */ public void UpdateDistribution(IEvolutionState state, Subpopulation subpop) { // % Sort by fitness and compute weighted mean into xmean // [arfitness, arindex] = sort(arfitness); % minimization // xmean = arx(:,arindex(1:mu))*weights; % recombination % Eq.39 // counteval += lambda; // only need partial sort? ((List <Individual>)subpop.Individuals).Sort(); SimpleMatrixD artmp = new SimpleMatrixD(GenomeSize, mu); SimpleMatrixD xold = xmean; xmean = new SimpleMatrixD(GenomeSize, 1); for (int i = 0; i < mu; i++) { DoubleVectorIndividual dvind = (DoubleVectorIndividual)subpop.Individuals[i]; // won't modify the genome SimpleMatrixD arz = new SimpleMatrixD(GenomeSize, 1, true, dvind.genome); arz = (arz.minus(xold).divide(sigma)); for (int j = 0; j < GenomeSize; j++) { xmean.set(j, 0, xmean.get(j, 0) + weights[i] * dvind.genome[j]); artmp.set(j, i, arz.get(j, 0)); } } // % Cumulation: Update evolution paths SimpleMatrixD y = xmean.minus(xold).divide(sigma); SimpleMatrixD bz = invsqrtC.mult(y); SimpleMatrixD bz_scaled = bz.scale(Math.Sqrt(cs * (2.0 - cs) * mueff)); ps = ps.scale(1.0 - cs).plus(bz_scaled); double h_sigma_value = ((ps.dot(ps) / (1.0 - Math.Pow(1.0 - cs, 2.0 * (state.Generation + 1)))) / GenomeSize); int hsig = (h_sigma_value < (2.0 + (4.0 / (GenomeSize + 1)))) ? 1 : 0; SimpleMatrixD y_scaled = y.scale(hsig * Math.Sqrt(cc * (2.0 - cc) * mueff)); pc = pc.scale(1.0 - cc).plus(y_scaled); // % Adapt covariance matrix C c = c.scale(1.0 - c1 - cmu); c = c.plus(pc.mult(pc.transpose()).plus(c.scale((1.0 - hsig) * cc * (2.0 - cc))).scale(c1)); c = c.plus((artmp.mult(SimpleMatrixD.diag(weights).mult(artmp.transpose()))).scale(cmu)); // % Adapt step-size sigma sigma = sigma * Math.Exp((cs / damps) * (ps.normF() / chiN - 1.0)); // % Update B and D from C if ((state.Generation - lastEigenDecompositionGeneration) > 1.0 / ((c1 + cmu) * GenomeSize * 10.0)) { lastEigenDecompositionGeneration = state.Generation; // make sure the matrix is symmetric (it should be already) // not sure if this is necessary for (int i = 0; i < GenomeSize; i++) { for (int j = 0; j < i; j++) { c.set(j, i, c.get(i, j)); } } // this copy gets modified by the decomposition DMatrixRMaj copy = c.copy().getMatrix(); EigenDecomposition <DMatrixRMaj> eig = DecompositionFactory_DDRM.eig(GenomeSize, true, true); if (eig.decompose(copy)) { SimpleMatrixD dinv = new SimpleMatrixD(GenomeSize, GenomeSize); for (int i = 0; i < GenomeSize; i++) { double eigrt = Math.Sqrt(eig.getEigenValue(i).real); d.set(i, i, eigrt); dinv.set(i, i, 1 / eigrt); CommonOps_DDRM.insert(eig.getEigenVector(i), b.getMatrix(), 0, i); } invsqrtC = b.mult(dinv.mult(b.transpose())); CommonOps_DDRM.mult(b.getMatrix(), d.getMatrix(), bd); } else { state.Output.Fatal("CMA-ES eigendecomposition failed. "); } } CommonOps_DDRM.scale(sigma, bd, sbd); // % Break, if fitness is good enough or condition exceeds 1e14, better termination methods are advisable // if arfitness(1) <= stopfitness || max(D) > 1e7 * min(D) // break; // end if (useAltTermination && CommonOps_DDRM.elementMax(d.diag().getMatrix()) > 1e7 * CommonOps_DDRM.elementMin(d.diag().getMatrix())) { state.Evaluator.SetRunCompleted("CMAESSpecies: Stopped because matrix condition exceeded limit."); } }
public virtual void mult(DMatrixRMaj A, DMatrixRMaj B, DMatrixRMaj output) { CommonOps_DDRM.mult(A, B, output); }
public override Individual NewIndividual(IEvolutionState state, int thread) { Individual newind = base.NewIndividual(state, thread); IMersenneTwister random = state.Random[thread]; if (!(newind is DoubleVectorIndividual)) // uh oh { state.Output.Fatal( "To use CMAESSpecies, the species must be initialized with a DoubleVectorIndividual. But it contains a " + newind); } DoubleVectorIndividual dvind = (DoubleVectorIndividual)(newind); DMatrixRMaj genome = DMatrixRMaj.wrap(GenomeSize, 1, dvind.genome); DMatrixRMaj temp = new DMatrixRMaj(GenomeSize, 1); // arz(:,k) = randn(N,1); % standard normally distributed vector // arx(:,k) = xmean + sigma*(B*D*arz(:,k)); int tries = 0; while (true) { for (int i = 0; i < GenomeSize; i++) { dvind.genome[i] = random.NextGaussian(); } CommonOps_DDRM.mult(sbd, genome, temp); // temp = sigma*b*d*genome; CommonOps_DDRM.add(temp, xmean.getMatrix(), genome); // genome = temp + xmean; bool invalid_value = false; for (int i = 0; i < GenomeSize; i++) { if (dvind.genome[i] < MinGenes[i] || dvind.genome[i] > MaxGenes[i]) { if (useAltGenerator && tries > altGeneratorTries) { // instead of just failing, we're going to select uniformly from // possible values for this particular gene. dvind.genome[i] = state.Random[thread].NextDouble() * (MaxGenes[i] - MinGenes[i]) + MinGenes[i]; } else { invalid_value = true; break; } } } if (invalid_value) { if (++tries > MAX_TRIES_BEFORE_WARNING) { state.Output.WarnOnce( "CMA-ES may be slow because many individuals are being generated which\n" + "are outside the min/max gene bounds. If an individual violates a single\n" + "gene bounds, it is rejected, so as the number of genes grows, the\n" + "probability of this happens increases exponentially. You can deal\n" + "with this by decreasing sigma. Alternatively you can use set\n" + "pop.subpop.0.alternative-generation=true (see the manual).\n" + "Finally, if this is happening during initialization, you might also\n" + "change pop.subpop.0.species.covariance=scaled.\n"); } continue; } return(newind); } }
public override void Setup(IEvolutionState state, IParameter paramBase) { base.Setup(state, paramBase); IMersenneTwister random = state.Random[0]; IParameter def = DefaultBase; IParameter subpopBase = paramBase.Pop(); IParameter subpopDefaultBase = ECDefaults.ParamBase.Push(Subpopulation.P_SUBPOPULATION); if (!state.Parameters.ParameterExists(paramBase.Push(P_SIGMA), def.Push(P_SIGMA))) { state.Output.Message("CMA-ES sigma was not provided, defaulting to 1.0"); sigma = 1.0; } else { sigma = state.Parameters.GetDouble(paramBase.Push(P_SIGMA), def.Push(P_SIGMA), 0.0); if (sigma <= 0) { state.Output.Fatal("If CMA-ES sigma is provided, it must be > 0.0", paramBase.Push(P_SIGMA), def.Push(P_SIGMA)); } } double[] cvals = new double[GenomeSize]; string covarianceInitialization = state.Parameters.GetStringWithDefault(paramBase.Push(P_COVARIANCE), def.Push(P_COVARIANCE), V_IDENTITY); string covs = "Initial Covariance: <"; for (int i = 0; i < GenomeSize; i++) { if (i > 0) { covs += ", "; } if (covarianceInitialization.Equals(V_SCALED)) { cvals[i] = (MaxGenes[i] - MinGenes[i]); } else if (covarianceInitialization.Equals(V_IDENTITY)) { cvals[i] = 1.0; } else { state.Output.Fatal("Invalid covariance initialization type " + covarianceInitialization, paramBase.Push(P_COVARIANCE), def.Push(P_COVARIANCE)); } // cvals is standard deviations, so we change them to variances now cvals[i] *= cvals[i]; covs += cvals[i]; } state.Output.Message(covs + ">"); // set myself up and define my initial distribution here int n = GenomeSize; b = SimpleMatrixD.identity(n); c = new SimpleMatrixD(CommonOps_DDRM.diag(cvals)); d = SimpleMatrixD.identity(n); bd = CommonOps_DDRM.identity(n, n); sbd = CommonOps_DDRM.identity(n, n); invsqrtC = SimpleMatrixD.identity(n); // Here we do one FIRST round of eigendecomposition, because newIndividual needs // a valid version of sbd. If c is initially the identity matrix (and sigma = 1), // then sbd is too, and we're done. But if c is scaled in any way, we need to compute // the proper value of sbd. Along the way we'll wind up computing b, d, bd, and invsqrtC EigenDecomposition <DMatrixRMaj> eig = DecompositionFactory_DDRM.eig(GenomeSize, true, true); if (eig.decompose(c.copy().getMatrix())) { SimpleMatrixD dinv = new SimpleMatrixD(GenomeSize, GenomeSize); for (int i = 0; i < GenomeSize; i++) { double eigrt = Math.Sqrt(eig.getEigenValue(i).real); d.set(i, i, eigrt); dinv.set(i, i, 1 / eigrt); CommonOps_DDRM.insert(eig.getEigenVector(i), b.getMatrix(), 0, i); } invsqrtC = b.mult(dinv.mult(b.transpose())); CommonOps_DDRM.mult(b.getMatrix(), d.getMatrix(), bd); } else { state.Output.Fatal("CMA-ES eigendecomposition failed. "); } CommonOps_DDRM.scale(sigma, bd, sbd); // End FIRST round of eigendecomposition // Initialize dynamic (internal) strategy parameters and constants pc = new SimpleMatrixD(n, 1); ps = new SimpleMatrixD(n, 1); // evolution paths for C and sigma chiN = Math.Sqrt(n) * (1.0 - 1.0 / (4.0 * n) + 1.0 / (21.0 * n * n)); // expectation of ||N(0,I)|| == norm(randn(N,1)) xmean = new SimpleMatrixD(GenomeSize, 1); bool meanSpecified = false; string val = state.Parameters.GetString(paramBase.Push(P_MEAN), def.Push(P_MEAN)); if (val != null) { meanSpecified = true; if (val.Equals(V_CENTER)) { for (int i = 0; i < GenomeSize; i++) { xmean.set(i, 0, (MaxGenes[i] + MinGenes[i]) / 2.0); } } else if (val.Equals(V_ZERO)) { for (int i = 0; i < GenomeSize; i++) { xmean.set(i, 0, 0); // it is this anyway } } else if (val.Equals(V_RANDOM)) { for (int i = 0; i < GenomeSize; i++) { xmean.set(i, 0, state.Random[0].NextDouble(true, true) * (MaxGenes[i] - MinGenes[i]) + MinGenes[i]); } } else { state.Output.Fatal("Unknown mean value specified: " + val, paramBase.Push(P_MEAN), def.Push(P_MEAN)); } } else { state.Output.Fatal("No default mean value specified. Loading full mean from parameters.", paramBase.Push(P_MEAN), def.Push(P_MEAN)); } bool nonDefaultMeanSpecified = false; for (int i = 0; i < GenomeSize; i++) { double m_i = 0; try { m_i = state.Parameters.GetDouble(paramBase.Push(P_MEAN).Push("" + i), def.Push(P_MEAN).Push("" + i)); xmean.set(i, 0, m_i); nonDefaultMeanSpecified = true; } catch (FormatException e) { if (!meanSpecified) { state.Output.Error( "No default mean value was specified, but CMA-ES mean index " + i + " is missing or not a number.", paramBase.Push(P_MEAN).Push("" + i), def.Push(P_MEAN).Push("" + i)); } } } state.Output.ExitIfErrors(); if (nonDefaultMeanSpecified && meanSpecified) { state.Output.Warning("A default mean value was specified, but certain mean values were overridden."); } string mes = "Initial Mean: <"; for (int i = 0; i < GenomeSize - 1; i++) { mes = mes + xmean.get(i, 0) + ", "; } mes = mes + xmean.get(GenomeSize - 1, 0) + ">"; state.Output.Message(mes); if (!state.Parameters.ParameterExists(paramBase.Push(P_LAMBDA), def.Push(P_LAMBDA))) { lambda = 4 + (int)Math.Floor(3 * Math.Log(n)); } else { lambda = state.Parameters.GetInt(paramBase.Push(P_LAMBDA), def.Push(P_LAMBDA), 1); if (lambda <= 0) { state.Output.Fatal("If the CMA-ES lambda parameter is provided, it must be a valid integer > 0", paramBase.Push(P_LAMBDA), def.Push(P_LAMBDA)); } } if (!state.Parameters.ParameterExists(paramBase.Push(P_MU), def.Push(P_MU))) { mu = (int)(Math.Floor(lambda / 2.0)); } else { mu = state.Parameters.GetInt(paramBase.Push(P_MU), def.Push(P_MU), 1); if (mu <= 0) { state.Output.Fatal("If the CMA-ES mu parameter is provided, it must be a valid integer > 0", paramBase.Push(P_MU), def.Push(P_MU)); } } if (mu > lambda) // uh oh { state.Output.Fatal("CMA-ES mu must be <= lambda. Presently mu=" + mu + " and lambda=" + lambda); } weights = new double[mu]; bool weightsSpecified = false; for (int i = 0; i < mu; i++) { if (state.Parameters.ParameterExists(paramBase.Push(P_WEIGHTS).Push("" + i), def.Push(P_WEIGHTS).Push("" + i))) { state.Output.Message("CMA-ES weight index " + i + " specified. Loading all weights from parameters."); weightsSpecified = true; break; } } if (weightsSpecified) { for (int i = 0; i < mu; i++) { double m_i = 0; try { weights[i] = state.Parameters.GetDouble(paramBase.Push(P_WEIGHTS).Push("" + i), def.Push(P_WEIGHTS).Push("" + i)); } catch (FormatException e) { state.Output.Error("CMA-ES weight index " + i + " missing or not a number.", paramBase.Push(P_WEIGHTS).Push("" + i), def.Push(P_WEIGHTS).Push("" + i)); } } state.Output.ExitIfErrors(); } else { for (int i = 0; i < mu; i++) { weights[i] = Math.Log((lambda + 1.0) / (2.0 * (i + 1))); } } // normalize double sum = 0.0; for (int i = 0; i < mu; i++) { sum += weights[i]; } for (int i = 0; i < mu; i++) { weights[i] /= sum; } // compute mueff double sumSqr = 0.0; for (int i = 0; i < mu; i++) { sumSqr += weights[i] * weights[i]; } mueff = 1.0 / sumSqr; mes = "Weights: <"; for (int i = 0; i < weights.Length - 1; i++) { mes = mes + weights[i] + ", "; } mes = mes + (weights.Length - 1) + ">"; state.Output.Message(mes); useAltTermination = state.Parameters.GetBoolean(paramBase.Push(P_ALTERNATIVE_TERMINATION), def.Push(P_ALTERNATIVE_TERMINATION), false); useAltGenerator = state.Parameters.GetBoolean(paramBase.Push(P_ALTERNATIVE_GENERATOR), def.Push(P_ALTERNATIVE_GENERATOR), false); altGeneratorTries = state.Parameters.GetIntWithDefault(paramBase.Push(P_ALTERNATIVE_GENERATOR_TRIES), def.Push(P_ALTERNATIVE_GENERATOR_TRIES), DEFAULT_ALT_GENERATOR_TRIES); if (altGeneratorTries < 1) { state.Output.Fatal( "If specified (the default is " + DEFAULT_ALT_GENERATOR_TRIES + "), alt-generation-tries must be >= 1", paramBase.Push(P_ALTERNATIVE_GENERATOR_TRIES), def.Push(P_ALTERNATIVE_GENERATOR_TRIES)); } if (!state.Parameters.ParameterExists(paramBase.Push(P_CC), def.Push(P_CC))) { cc = (4.0 + mueff / n) / (n + 4.0 + 2.0 * mueff / n); // time constant for cumulation for C } else { cc = state.Parameters.GetDoubleWithMax(paramBase.Push(P_CC), def.Push(P_CC), 0.0, 1.0); if (cc < 0.0) { state.Output.Fatal( "If the CMA-ES cc parameter is provided, it must be a valid number in the range [0,1]", paramBase.Push(P_CC), def.Push(P_CC)); } } if (!state.Parameters.ParameterExists(paramBase.Push(P_CS), def.Push(P_CS))) { cs = (mueff + 2.0) / (n + mueff + 5.0); // t-const for cumulation for sigma control } else { cs = state.Parameters.GetDoubleWithMax(paramBase.Push(P_CS), def.Push(P_CS), 0.0, 1.0); if (cs < 0.0) { state.Output.Fatal( "If the CMA-ES cs parameter is provided, it must be a valid number in the range [0,1]", paramBase.Push(P_CS), def.Push(P_CS)); } } if (!state.Parameters.ParameterExists(paramBase.Push(P_C1), def.Push(P_C1))) { c1 = 2.0 / ((n + 1.3) * (n + 1.3) + mueff); // learning rate for rank-one update of C } else { c1 = state.Parameters.GetDouble(paramBase.Push(P_C1), def.Push(P_C1), 0.0); if (c1 < 0) { state.Output.Fatal("If the CMA-ES c1 parameter is provided, it must be a valid number >= 0.0", paramBase.Push(P_C1), def.Push(P_C1)); } } if (!state.Parameters.ParameterExists(paramBase.Push(P_CMU), def.Push(P_CMU))) { cmu = Math.Min(1.0 - c1, 2.0 * (mueff - 2.0 + 1.0 / mueff) / ((n + 2.0) * (n + 2.0) + mueff)); } else { cmu = state.Parameters.GetDouble(paramBase.Push(P_CMU), def.Push(P_CMU), 0.0); if (cmu < 0) { state.Output.Fatal("If the CMA-ES cmu parameter is provided, it must be a valid number >= 0.0", paramBase.Push(P_CMU), def.Push(P_CMU)); } } if (c1 > (1 - cmu)) // uh oh { state.Output.Fatal("CMA-ES c1 must be <= 1 - cmu. You are using c1=" + c1 + " and cmu=" + cmu); } if (cmu > (1 - c1)) // uh oh { state.Output.Fatal("CMA-ES cmu must be <= 1 - c1. You are using cmu=" + cmu + " and c1=" + c1); } if (!state.Parameters.ParameterExists(paramBase.Push(P_DAMPS), def.Push(P_DAMPS))) { damps = 1.0 + 2.0 * Math.Max(0.0, Math.Sqrt((mueff - 1.0) / (n + 1.0)) - 1.0) + cs; // damping for sigma } else { damps = state.Parameters.GetDouble(paramBase.Push(P_DAMPS), def.Push(P_DAMPS), 0.0); if (damps <= 0) { state.Output.Fatal("If the CMA-ES damps parameter is provided, it must be a valid number > 0.0", paramBase.Push(P_DAMPS), def.Push(P_DAMPS)); } } double damps_min = 0.5; double damps_max = 2.0; if (damps > damps_max || damps < damps_min) { state.Output.Warning("CMA-ES damps ought to be close to 1. You are using damps = " + damps); } state.Output.Message("lambda: " + lambda); state.Output.Message("mu: " + mu); state.Output.Message("mueff: " + mueff); state.Output.Message("cmu: " + cmu); state.Output.Message("c1: " + c1); state.Output.Message("cc: " + cc); state.Output.Message("cs: " + cs); state.Output.Message("damps: " + damps); }
/** * <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); }
public void mult(Matrix A, Matrix B, Matrix output) { CommonOps_DDRM.mult((DMatrixRMaj)A, (DMatrixRMaj)B, (DMatrixRMaj)output); }
/** * 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; } } }