Example #1
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;
  }
 /**
  * True if the subswarm is active and all particles are completely converged (i.e. the stddev over
  * the past 3 iterations is &lt; epsilson)
  */
 @Override
 public boolean shouldDeactivateSubswarm(ParticleSubSwarmOptimization subswarm) {
   if (!subswarm.isActive()) {
     return false;
   }
   if (subswarm.getFitnessArchiveSize() < haltingWindow) {
     EVAERROR.errorMsgOnce(
         "Warning: halting window length "
             + haltingWindow
             + " too long for sub swarm template, which stores only "
             + subswarm.getFitnessArchiveSize()
             + " fitness values!");
   }
   return (isConverged(subswarm.getPopulation()));
 }
 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));
  }
  @Override
  public void optimize() {
    //  System.out.println("opt. called");
    AbstractEAIndividual indy;
    //      if ((this.indyhash == null) || (this.indyhash.size() <1)) initialize();

    for (int i = 0; i < this.population.size(); i++) {
      indy = this.population.get(i);
      if (!indy.hasData(gradientKey)) {
        // System.out.println("new indy to hash");
        //        Hashtable history = new Hashtable();
        int[] lock = new int[((InterfaceDataTypeDouble) indy).getDoubleData().length];
        double[] wstepsize = new double[((InterfaceDataTypeDouble) indy).getDoubleData().length];
        for (int li = 0; li < lock.length; li++) {
          lock[li] = 0;
        }
        for (int li = 0; li < lock.length; li++) {
          wstepsize[li] = 1.0;
        }
        double fitness = 0;
        indy.putData(lockKey, lock);
        indy.putData(lastFitnessKey, fitness);
        indy.putData(stepSizeKey, globalinitstepsize);
        indy.putData(wStepSizeKey, wstepsize);
        //        indyhash.put(indy, history);
      } else {
        // System.out.println("indy already in hash");
      }
    }
    // System.out.println("hashtable built");
    for (int i = 0; i < this.population.size(); i++) {

      indy = this.population.get(i);
      double[][] range = ((InterfaceDataTypeDouble) indy).getDoubleRange();
      double[] params = ((InterfaceDataTypeDouble) indy).getDoubleData();
      indy.putData(oldParamsKey, params);

      int[] lock = (int[]) indy.getData(lockKey);
      double indystepsize = (Double) indy.getData(stepSizeKey);

      if ((this.optimizationProblem instanceof InterfaceFirstOrderDerivableProblem)
          && (indy instanceof InterfaceDataTypeDouble)) {
        for (int iterations = 0; iterations < this.iterations; iterations++) {

          double[] oldgradient =
              indy.hasData(gradientKey) ? (double[]) indy.getData(gradientKey) : null;
          double[] wstepsize = (double[]) indy.getData(wStepSizeKey);
          double[] oldchange = null;

          double[] gradient =
              ((InterfaceFirstOrderDerivableProblem) optimizationProblem)
                  .getFirstOrderGradients(params);
          if ((oldgradient != null) && (wstepsize != null)) { // LOCAL adaption
            for (int li = 0; li < wstepsize.length; li++) {
              double prod = gradient[li] * oldgradient[li];
              if (prod < 0) {
                wstepsize[li] = wDecreaseStepSize * wstepsize[li];
              } else if (prod > 0) {
                wstepsize[li] = wIncreaseStepSize * wstepsize[li];
              }
              wstepsize[li] = (wstepsize[li] < localminstepsize) ? localminstepsize : wstepsize[li];
              wstepsize[li] = (wstepsize[li] > localmaxstepsize) ? localmaxstepsize : wstepsize[li];
            }
          }
          double[] newparams = new double[params.length];
          indy.putData(gradientKey, gradient);
          double[] change = new double[params.length];
          if (indy.hasData(changesKey)) {
            oldchange = (double[]) indy.getData(changesKey);
          }
          boolean dograddesc = (this.momentumterm) && (oldchange != null);

          for (int j = 0; j < newparams.length; j++) {
            if (lock[j] == 0) {
              double tempstepsize = 1;
              if (this.localStepSizeAdaption) {
                tempstepsize *= wstepsize[j];
              }
              if (this.globalStepSizeAdaption) {
                tempstepsize *= indystepsize;
              }
              double wchange =
                  signum(tempstepsize * gradient[j])
                      * Math.min(
                          maximumabsolutechange,
                          Math.abs(tempstepsize * gradient[j])); // indystepsize * gradient[j];
              if (this.manhattan) {
                wchange = this.signum(wchange) * tempstepsize;
              }
              if (dograddesc) {
                wchange += this.momentumweigth * oldchange[j];
              }
              newparams[j] = params[j] - wchange;
              if (newparams[j] < range[j][0]) {
                newparams[j] = range[j][0];
              }
              if (newparams[j] > range[j][1]) {
                newparams[j] = range[j][1];
              }
              //              for (int g = 0; g < newparams.length; g++) {
              //                System.out.println("Param " + g +": " + newparams[g]);
              //              }
              change[j] += wchange;
            } else {
              lock[j]--;
            }
          }
          params = newparams;

          indy.putData(changesKey, change);
        } // end loop iterations

        ((InterfaceDataTypeDouble) indy).setDoubleGenotype(params);

      } // end if ((this.problem instanceof InterfaceFirstOrderDerivableProblem) && (indy instanceof
      // InterfaceDataTypeDouble)) {
      else {
        String msg =
            "Warning, problem of type InterfaceFirstOrderDerivableProblem and template of type InterfaceDataTypeDouble is required for "
                + this.getClass();
        EVAERROR.errorMsgOnce(msg);
        Class<?>[] clsArr =
            ReflectPackage.getAssignableClasses(
                InterfaceFirstOrderDerivableProblem.class.getName(), true, true);
        msg += " (available: ";
        for (Class<?> cls : clsArr) {
          msg = msg + " " + cls.getSimpleName();
        }
        msg += ")";
        throw new RuntimeException(msg);
      }
    } // for loop population size

    this.optimizationProblem.evaluate(this.population);
    population.incrGeneration();

    if (this.recovery) {
      for (int i = 0; i < this.population.size(); i++) {
        indy = this.population.get(i);
        if (indy.getFitness()[0] > recoverythreshold) {

          ((InterfaceDataTypeDouble) indy)
              .setDoublePhenotype((double[]) indy.getData(oldParamsKey));
          double[] changes = (double[]) indy.getData(changesKey);
          int[] lock = (int[]) indy.getData(lockKey);

          int indexmaxchange = 0;
          double maxchangeval = Double.NEGATIVE_INFINITY;
          for (int j = 0; j < changes.length; j++) {
            if ((changes[j] > maxchangeval) && (lock[j] == 0)) {
              indexmaxchange = j;
              maxchangeval = changes[j];
            }
          }
          lock[indexmaxchange] = recoverylocksteps;
          indy.putData(lockKey, lock);
        } else {
        }
      }
      this.optimizationProblem.evaluate(this.population);
      population.incrGeneration();
    }

    if (this.globalStepSizeAdaption) {

      // System.out.println("gsa main");
      for (int i = 0; i < this.population.size(); i++) {
        indy = this.population.get(i);

        if (indy.getData(lastFitnessKey) != null) {
          double lastfit = (Double) indy.getData(lastFitnessKey);
          double indystepsize = (Double) indy.getData(stepSizeKey);

          if (lastfit < indy.getFitness()[0]) { // GLOBAL adaption
            indystepsize *= wDecreaseStepSize;
          } else {
            indystepsize *= wIncreaseStepSize;
          }
          indystepsize = (indystepsize > globalmaxstepsize) ? globalmaxstepsize : indystepsize;
          indystepsize = (indystepsize < globalminstepsize) ? globalminstepsize : indystepsize;
          indy.putData(stepSizeKey, indystepsize);
        }

        indy.putData(lastFitnessKey, indy.getFitness()[0]);
      }
    }

    this.firePropertyChangedEvent(Population.NEXT_GENERATION_PERFORMED);
  }