private double[] mutate(CMAParamSet params, double[] x, double[][] range, int count) {
   int dim = range.length;
   if (!Mathematics.isInRange(params.meanX, range)) { // TODO Im not sure why this can happen...
     System.err.println("Error in MutateESRankMuCMA.mutate !");
     Mathematics.projectToRange(params.meanX, range);
   }
   //		System.out.println("--- In mutate!");
   if (params != null && (params.firstAdaptionDone)) {
     double[] sampl = new double[dim]; // generate scaled random vector (D * z)
     for (int i = 0; i < dim; ++i) {
       sampl[i] = Math.sqrt(params.eigenvalues[i]) * RNG.gaussianDouble(1.);
       if (Double.isNaN(sampl[i])) sampl[i] = 0;
     }
     //			System.out.println("Sampling around " + BeanInspector.toString(meanX));
     /* add mutation (sigma * B * (D*z)) */
     addMutationStep(params, x, sampl);
     int cnt = 0;
     while (!Mathematics.isInRange(x, range)) {
       //			     % You may handle constraints here. You may either resample
       //			    % arz(:,k) and/or multiply it with a factor between -1 and 1
       //			    % (the latter will decrease the overall step size) and
       //			    % recalculate arx accordingly. Do not change arx or arz in any
       //			    % other way.
       // multiply sampl by a no in [-1,1] and try again
       double r; // actually we use [-1,-0.5] or [0.5, 1]
       cnt++;
       if (cnt > 10 * x.length) {
         // well... lets give it up. Probably the meanX is close to the bounds in several
         // dimensions
         // which is unlikely to be solved by random sampling.
         //					if (!Mathematics.isInRange(params.meanX, range)) {
         //						System.err.println("Error in MutateESRankMuCMA.mutate !"); break;
         //					}
         r = 0;
       } else {
         r = RNG.randomDouble(-0.5, 0.5);
         if (Math.abs(r) < 0.5) r += Math.signum(r) * 0.5; // r is in [-1,-0.5] or [0.5,1]
       }
       //				System.out.println("Reducing step by " + r + " for " +
       // BeanInspector.toString(params.meanX));
       Mathematics.svMult(r, sampl, sampl);
       addMutationStep(params, x, sampl);
     }
   } else {
     if (params == null) {
       System.err.println(
           "Error in MutateESRankMuCMA: parameter set was null! Skipping mutation...");
     } // no valid meanX yet, so just do a gaussian jump with sigma
     for (int i = 0; i < dim; ++i) {
       x[i] += RNG.gaussianDouble(getSigma(params, i));
       checkValidDouble(x[i]);
     }
   }
   if (!Mathematics.isInRange(params.meanX, range)) {
     System.err.println("Error B in MutateESRankMuCMA.mutate !");
   }
   if (TRACE_1) System.out.println("mutated indy: " + BeanInspector.toString(x));
   return x;
 }
  /**
   * Requires selected population to be sorted by fitness.
   *
   * @param params refering parameter set
   * @param iterations number of iterations performed
   * @param selected selected population
   * @return true if the parameters seem ok or were corrected, false if new parameters must be
   *     produced
   */
  private boolean testAndCorrectNumerics(
      CMAParamSet params, int iterations, Population selected) { // not much left here
    boolean corrected = true;
    /* Flat Fitness, Test if function values are identical */
    if (iterations > 1 && (selected.size() > 1)) {
      // selected pop is sorted
      if (nearlySame(
          selected.getEAIndividual(0).getFitness(),
          selected.getEAIndividual(selected.size() - 1).getFitness())) {
        if (TRACE_1)
          System.err.println(
              "flat fitness landscape, consider reformulation of fitness, step-size increased");
        params.sigma *= Math.exp(0.2 + params.c_sig / params.d_sig);
        //    			sigma=0.1;
      }
    }

    if (!checkValidDouble(params.sigma)) {
      System.err.println("Error, unstable sigma!");
      corrected = false;
      //        	params.sigma=params.firstSigma; // MK TODO
      //        	System.err.println(
    }

    /* Align (renormalize) scale C (and consequently sigma) */
    /* e.g. for infinite stationary state simulations (noise
     * handling needs to be introduced for that) */
    double fac = 1.;
    double minEig = 1e-12;
    double maxEig = 1e8;
    if (Mathematics.max(params.eigenvalues) < minEig)
      fac = 1. / Math.sqrt(Mathematics.max(params.eigenvalues));
    else if (Mathematics.min(params.eigenvalues) > maxEig)
      fac = 1. / Math.sqrt(Mathematics.min(params.eigenvalues));

    if (fac != 1.) {
      //    		System.err.println("Scaling by " + fac);
      params.sigma /= fac;
      for (int i = 0; i < params.meanX.length; ++i) {
        params.pathC[i] *= fac;
        params.eigenvalues[i] *= fac * fac;
        for (int j = 0; j <= i; ++j) {
          params.mC.set(i, j, params.mC.get(i, j) * fac * fac);
          if (i != j) params.mC.set(j, i, params.mC.get(i, j));
        }
      }
    }
    return corrected;
  } // Test...
  private double[] mutateOrig(CMAParamSet params, double[] x, double[][] range, int count) {
    int dim = range.length;
    int maxRetries;

    if (checkRange) maxRetries = 100 * dim;
    else maxRetries = 0; // take the first sample, not matter in or out of range
    do { // this is a loop in case that the range needs to be checked and the current sampling fails
         // to keep the range
      if (params != null && (params.firstAdaptionDone)) {
        double[] sampl = new double[dim]; // generate scaled random vector (D * z)
        for (int i = 0; i < dim; ++i) {
          sampl[i] = Math.sqrt(params.eigenvalues[i]) * RNG.gaussianDouble(1.);
          if (Double.isNaN(sampl[i])) sampl[i] = 0;
        }
        //			System.out.println("Sampling around " + BeanInspector.toString(meanX));
        /* add mutation (sigma * B * (D*z)) */
        for (int i = 0; i < dim; ++i) {
          double sum = 0.;
          for (int j = 0; j < dim; ++j) sum += params.mB.get(i, j) * sampl[j];
          x[i] = params.meanX[i] + getSigma(params, i) * sum;
          checkValidDouble(x[i]);
        }
      } else {
        if (params == null) {
          System.err.println(
              "Error in MutateESRankMuCMA: parameter set was null! Skipping mutation...");
        } // no valid meanX yet, so just do a gaussian jump with sigma
        for (int i = 0; i < dim; ++i) {
          x[i] += RNG.gaussianDouble(getSigma(params, i));
          checkValidDouble(x[i]);
        }
      }
    } while ((maxRetries--) > 0 && !(Mathematics.isInRange(x, range)));
    if (checkRange && !(Mathematics.isInRange(x, range)))
      return repairMutation(x, range); // allow some nice tries before using brute force
    else return x;
  }
Ejemplo n.º 4
0
  /**
   * Initializes the CMA parameter set for given mu, lambda and a population. The initialSigma
   * parameter is used as initial sigma directly unless it is <0, in that case the average range is
   * used as initial sigma.
   *
   * @param params the CMA parameter set to be used - its data are overwritten
   * @param mu ES mu parameter
   * @param lambda ES lambda parameter
   * @param pop associated Population
   * @param initialSigma initial sigma or -1 to indicate the usage of average range
   * @return
   */
  public static CMAParamSet initCMAParams(
      CMAParamSet params,
      int mu,
      int lambda,
      double[] center,
      double[][] range,
      double initialSigma) {
    // those are from initialize:
    params.firstAdaptionDone = false;
    params.range = range;

    int dim = params.range.length;
    params.eigenvalues = new double[dim];
    Arrays.fill(params.eigenvalues, 1.);
    params.meanX = new double[dim];
    params.pathC = new double[dim];
    params.pathS = new double[dim];

    params.mC = Matrix.identity(dim, dim);
    params.mB = Matrix.identity(dim, dim);

    // from adaptAfterSel
    params.weights = initWeights(mu, lambda);
    double muEff = getMuEff(params.weights, mu);
    params.c_sig = (muEff + 2) / (muEff + dim + 3);
    //		c_u_sig = Math.sqrt(c_sig * (2.-c_sig));
    params.d_sig = params.c_sig + 1 + 2 * Math.max(0, Math.sqrt((muEff - 1) / (dim + 1)) - 1);

    if (initialSigma < 0) { // this means we scale the average range
      if (initialSigma != -0.25 && (initialSigma != -0.5)) {
        EVAERROR.errorMsgOnce("Warning, unexpected initial sigma in CMAParamSet!");
      }
      initialSigma = -initialSigma * Mathematics.getAvgRange(params.range);
    }
    if (initialSigma <= 0) {
      EVAERROR.errorMsgOnce("warning: initial sigma <= zero! Working with converged population?");
      initialSigma = 10e-10;
    }
    params.sigma = initialSigma;
    //		System.out.println("INitial sigma: "+sigma);
    params.firstSigma = params.sigma;
    //		System.out.println("new center is " + BeanInspector.toString(center));
    params.meanX = center; // this might be ok?
    return params;
  }
  /**
   * From Auger&Hansen, CEC '05, stopping criterion noeffectaxis.
   *
   * @param d
   * @param gen
   * @return
   */
  public boolean testNoChangeAddingDevAxis(Population pop, double d, int gen) {
    //		  if all(xmean == xmean + 0.1*sigma*BD(:,1+floor(mod(countiter,N))))
    //	    i = 1+floor(mod(countiter,N));
    //		stopflag(end+1) = {'warnnoeffectaxis'};
    CMAParamSet params = (CMAParamSet) pop.getData(cmaParamsKey);
    int dim = params.meanX.length;
    int k = gen % dim;
    double[] ev_k = params.mB.getColumn(k);
    Mathematics.svMult(
        Math.sqrt(params.eigenvalues[k]), ev_k, ev_k); // this is now e_k*v_k = BD(:,...)

    int i = 0;
    boolean res = true;
    while (res && (i < dim)) {
      res = res && (params.meanX[i] == (params.meanX[i] + d * getSigma(params, i) * ev_k[i]));
      i++;
    }
    if (TRACE_TEST) if (res) System.out.println("testNoChangeAddingDevAxis hit");
    return res;
  }
 private double[] repairMutation(double[] x, double[][] range) {
   EVAERROR.errorMsgOnce(
       "Warning, brute-forcing constraints! Too large initial sigma? (pot. multiple errors)");
   Mathematics.projectToRange(x, range);
   return x;
 }
  /**
   * Perform the main adaption of sigma and C using evolution paths. The evolution path is deduced
   * from the center of the selected population compared to the old mean value. See Hansen&Kern 04
   * for further information.
   *
   * @param oldGen
   * @param selectedP
   */
  public void adaptAfterSelection(Population oldGen, Population selectedP) {
    Population selectedSorted =
        selectedP.getSortedBestFirst(new AbstractEAIndividualComparator(-1));

    int mu, lambda;
    mu = selectedP.size();
    lambda = oldGen.size();
    int generation = oldGen.getGeneration();
    if (mu >= lambda) {
      // try to override by oldGen additional data:
      if (oldGen.hasData(EvolutionStrategies.esMuParam))
        mu = (Integer) oldGen.getData(EvolutionStrategies.esMuParam);
      if (oldGen.hasData(EvolutionStrategies.esLambdaParam))
        lambda = (Integer) oldGen.getData(EvolutionStrategies.esLambdaParam);
    }
    if (mu >= lambda) {
      mu = Math.max(1, lambda / 2);
      EVAERROR.errorMsgOnce(
          "Warning: invalid mu/lambda ratio! Setting mu to lambda/2 = "
              + mu
              + ", lambda = "
              + lambda);
    }
    CMAParamSet params;
    if (oldGen.getGeneration()
        <= 1) { // init new param set. At gen < 1 we shouldnt be called, but better do it once too
                // often
      if (oldGen.hasData(cmaParamsKey))
        params =
            CMAParamSet.initCMAParams(
                (CMAParamSet) oldGen.getData(cmaParamsKey),
                mu,
                lambda,
                oldGen,
                getInitSigma(oldGen));
      else params = CMAParamSet.initCMAParams(mu, lambda, oldGen, getInitSigma(oldGen));
    } else {
      if (!oldGen.hasData(cmaParamsKey)) {
        if (oldGen.getGeneration() > 1)
          EVAERROR.errorMsgOnce("Error: population lost cma parameters. Incompatible optimizer?");
        params = CMAParamSet.initCMAParams(mu, lambda, oldGen, getInitSigma(oldGen));
      } else params = (CMAParamSet) oldGen.getData(cmaParamsKey);
    }

    if (lambda == 1
        && (oldGen.size() == 1)
        && (selectedP.size() == 1)
        && (oldGen.getEAIndividual(0).equals(selectedP.getEAIndividual(0)))) {
      // nothing really happened, so do not adapt and just store default params
      lastParams = (CMAParamSet) params.clone();
      oldGen.putData(cmaParamsKey, params);
      selectedP.putData(cmaParamsKey, params);
      return;
    }

    if (TRACE_1) {
      System.out.println("WCMA adaptGenerational **********");
      //			System.out.println("newPop measures: " +
      // BeanInspector.toString(newPop.getPopulationMeasures()));
      System.out.println("mu_eff: " + CMAParamSet.getMuEff(params.weights, mu));
      System.out.println(params.toString());
      System.out.println("*********************************");
    }

    double[] newMeanX = calcMeanX(params.weights, selectedSorted);
    if (TRACE_1) System.out.println("newMeanX:  " + BeanInspector.toString(newMeanX));

    int dim = params.meanX.length;
    double[] BDz = new double[dim];
    for (int i = 0; i < dim; i++) {
        /* calculate xmean and BDz~N(0,C) */
      // Eq. 4 from HK04, most right term
      BDz[i] =
          Math.sqrt(CMAParamSet.getMuEff(params.weights, mu))
              * (newMeanX[i] - params.meanX[i])
              / getSigma(params, i);
    }
    //        if (TRACE_2) System.out.println("BDz is " + BeanInspector.toString(BDz));

    double[] newPathS = params.pathS.clone();
    double[] newPathC = params.pathC.clone();

    double[] zVect = new double[dim];
    /* calculate z := D^(-1) * B^(-1) * BDz into artmp, we could have stored z instead */
    for (int i = 0; i < dim; ++i) {
      double sum = 0.;
      for (int j = 0; j < dim; ++j) {
        sum += params.mB.get(j, i) * BDz[j]; // times B transposed, (Eq 4) in HK04
      }
      if (params.eigenvalues[i] < 0) {
        EVAERROR.errorMsgOnce(
            "Warning: negative eigenvalue in MutateESRankMuCMA! (possibly multiple cases)");
        zVect[i] = 0;
      } else {
        zVect[i] = sum / Math.sqrt(params.eigenvalues[i]);
        if (!checkValidDouble(zVect[i])) {
          System.err.println("Error, infinite zVect entry!");
          zVect[i] = 0; // TODO MK
        }
      }
    }

    /* cumulation for sigma (ps) using B*z */
    for (int i = 0; i < dim; ++i) {
      double sum = 0.;
      for (int j = 0; j < dim; ++j) sum += params.mB.get(i, j) * zVect[j];
      newPathS[i] =
          (1. - params.c_sig) * params.pathS[i]
              + Math.sqrt(params.c_sig * (2. - params.c_sig)) * sum;
      if (!checkValidDouble(newPathS[i])) {
        System.err.println("Error, infinite pathS!");
      }
    }
    //		System.out.println("pathS diff: " + BeanInspector.toString(Mathematics.vvSub(newPathS,
    // pathS)));
    //		System.out.println("newPathS is " + BeanInspector.toString(newPathS));

    double psNorm = Mathematics.norm(newPathS);

    double hsig = 0;
    if (psNorm / Math.sqrt(1. - Math.pow(1. - params.c_sig, 2. * generation)) / expRandStepLen
        < 1.4 + 2. / (dim + 1.)) {
      hsig = 1;
    }
    for (int i = 0; i < dim; ++i) {
      newPathC[i] =
          (1. - getCc()) * params.pathC[i] + hsig * Math.sqrt(getCc() * (2. - getCc())) * BDz[i];
      checkValidDouble(newPathC[i]);
    }

    // TODO missing: "remove momentum in ps"

    if (TRACE_1) {
      System.out.println("newPathC: " + BeanInspector.toString(newPathC));
      System.out.println("newPathS: " + BeanInspector.toString(newPathS));
    }

    if (TRACE_1) System.out.println("Bef: C is \n" + params.mC.toString());
    if (params.meanX == null) params.meanX = newMeanX;

    updateCov(params, newPathC, newMeanX, hsig, mu, selectedSorted);
    updateBD(params);

    if (TRACE_2) System.out.println("Aft: C is " + params.mC.toString());

    /* update of sigma */
    double sigFact = Math.exp(((psNorm / expRandStepLen) - 1) * params.c_sig / params.d_sig);
    if (Double.isInfinite(sigFact))
      params.sigma *= 10.; // in larger search spaces sigma tends to explode after init.
    else params.sigma *= sigFact;

    if (!testAndCorrectNumerics(params, generation, selectedSorted)) {
      // parameter seemingly exploded...
      params =
          CMAParamSet.initCMAParams(
              params,
              mu,
              lambda,
              params.meanX,
              ((InterfaceDataTypeDouble) oldGen.getEAIndividual(0)).getDoubleRange(),
              params.firstSigma);
    }

    if (TRACE_1) {
      System.out.println("sigma=" + params.sigma);
      System.out.print("psLen=" + (psNorm) + " ");
      outputParams(params, mu);
    }

    // take over data
    params.meanX = newMeanX;
    params.pathC = newPathC;
    params.pathS = newPathS;
    params.firstAdaptionDone = true;

    lastParams = (CMAParamSet) params.clone();
    oldGen.putData(cmaParamsKey, params);
    selectedP.putData(cmaParamsKey, params);
    //		if (TRACE_2) System.out.println("sampling around " + BeanInspector.toString(meanX));
  }