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); }
/// <summary> /// Copy matrix B into this matrix at location (insertRow, insertCol). /// </summary> public override void insertIntoThis(int insertRow, int insertCol, SimpleMatrixD B) { var bm = B.getMatrix(); CommonOps_DDRM.insert(bm, mat, insertRow, insertCol); }
/** 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 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); }
public void construct() { // make sure the last item is and end row if (!items[items.Count - 1].endRow) { endRow(); } // have to initialize some variable types first to get the actual size for (int i = 0; i < items.Count; i++) { items[i].initialize(); } setToRequiredSize(output.matrix); int matrixRow = 0; List <Item> row = new List <Item>(); for (int i = 0; i < items.Count; i++) { Item item = items[i]; if (item.endRow) { int expectedRows = 0; int numCols = 0; for (int j = 0; j < row.Count; j++) { Item v = row[j]; int numRows = v.getRows(); if (j == 0) { expectedRows = numRows; } else if (v.getRows() != expectedRows) { throw new InvalidOperationException("Row miss-matched. " + numRows + " " + v.getRows()); } if (v.matrix) { CommonOps_DDRM.insert(v.getMatrix(), output.matrix, matrixRow, numCols); } else if (v.variable.getType() == VariableType.SCALAR) { output.matrix.set(matrixRow, numCols, v.getValue()); } else if (v.variable.getType() == VariableType.INTEGER_SEQUENCE) { IntegerSequence sequence = ((VariableIntegerSequence)v.variable).sequence; int col = numCols; while (sequence.hasNext()) { output.matrix.set(matrixRow, col++, sequence.next()); } } else { throw new ParseError("Can't insert a variable of type " + v.variable.getType() + " inside a matrix!"); } numCols += v.getColumns(); } matrixRow += expectedRows; row.Clear(); } else { row.Add(item); } } }
/** * 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; } } }