如何在约束多目标优化中更快地生成初始种群

时间:2015-10-08 22:52:56

标签: java genetic-algorithm

我使用NSGA-II来解决约束MOOP,饲料配方问题。在初始化步骤中,我总是在接受并放入群体之前验证生成的具有约束需要的随机染色体。但这一步需要大约24小时的时间。

如果我没有验证染色体,给定的解决方案不符合约束条件。大多数解决方案只能满足8的营养约束。

在这种情况下,如何快速生成初始人口?

// method to generate a chromosome
public Variable[] createVariables() {
    Variable[] variables = new Variable[problem_.getNumberOfVariables()];

    Random random = new Random();
    boolean variablesConfirmed = false;
    FeedFormulation feedF = (FeedFormulation) problem_;

    while (!variablesConfirmed) {

        // generate a chromosome randomly, each genes in a chromosome have different lower and upper limit
        for (int var = 0; var < problem_.getNumberOfVariables(); var++) {
            variables[var] = new RealCustom(random, problem_.getLowerLimit(var), problem_.getUpperLimit(var));
        }

        // check if the generated chromosome meet constraint (nutrient needs)
        variablesConfirmed = checkVariable(feedF, variables);
    }

    return variables;
}

// method to check if the generated chromosome meet constraint (nutrient needs)
private boolean checkVariable(FeedFormulation feedF, Variable[] variables) {

    int numberConfirmedNutrient = 0;
    int numberUnconfirmedNutrient = 0;
    float unconfirmedNutrientPercentation = 75f;

    Set<String> nutrients = getnutrients(feedF.getIngredients());
    Map<String, Double> sumOfNutrientI;

    sumOfNutrientI = getSumOfNutrientI(getSumOfProportion(variables),
            nutrients,
            feedF.getIngredients(),
            getVariables(variables));

    NutrientNeeds nutrientNeeds = feedF.getAnimal().getNutrientNeeds();

    Set nutrientKeys = sumOfNutrientI.keySet();

    for (Iterator ky = nutrientKeys.iterator(); ky.hasNext();) {
        String key = (String) ky.next();

        // if nutrient (key) need has min and max limit
        if (nutrientNeeds.getNutrientNeed(key).getMax() != 0) {
            if ((sumOfNutrientI.get(key) > nutrientNeeds.getNutrientNeed(key).getMin()
                    || sumOfNutrientI.get(key) == nutrientNeeds.getNutrientNeed(key).getMin())
                    && (sumOfNutrientI.get(key) < nutrientNeeds.getNutrientNeed(key).getMax()
                    || sumOfNutrientI.get(key) == nutrientNeeds.getNutrientNeed(key).getMax())) {

                numberConfirmedNutrient++;

            } else {

                numberUnconfirmedNutrient++;

                if (numberUnconfirmedNutrient > 0) { break; }

            }
        } else { // if max nutrient (key) need = infinity
            if (sumOfNutrientI.get(key) > nutrientNeeds.getNutrientNeed(key).getMin()
                    || sumOfNutrientI.get(key) == nutrientNeeds.getNutrientNeed(key).getMin()) {

                numberConfirmedNutrient++;

            } else {

                numberUnconfirmedNutrient++;

                if (numberUnconfirmedNutrient > 0) { break; }
            }
        }
    }

    // return true if all nutrient need satisfied
    return numberConfirmedNutrient == nutrientKeys.size();
}

private double[] getVariables(Variable[] variables) {

    double[] x = new double[problem_.getNumberOfVariables()]; // variable values

    for (int i = 0; i < problem_.getNumberOfVariables(); i++) {
        x[i] = variables[i].getValue();
    }

    return x;
}

private double getSumOfProportion(Variable[] variables) {

    double[] x = getVariables(variables);
    double sumOfProportion = 0d;

    for (int i = 0; i < x.length; i++) {
        sumOfProportion += x[i];
    }

    return sumOfProportion;
}

private Map<String, Double> getSumOfNutrientI(double sumOfProportion, Set<String> nutrients,
        Ingredients choosenIngredients, double[] variables) {

    // store set of sum of i-th nutrient
    // key = nutrient name, value = nutrient content in feed ration
    Map<String, Double> sumOfNutrientI = new HashMap<>();

    for (String nutrien : nutrients) {
        double sumOfNutrientContent = 0;

        for (int j = 0; j < choosenIngredients.getIngredients().size(); j++) {

            // sum  = (j-th_ingredient_proportion / sum_of_proportion) * i-th_nutrient_content_in_j-th_ingredient
            sumOfNutrientContent
                    += ((variables[j] / sumOfProportion)
                    * choosenIngredients.getIngredients().get(j).getNutrien(nutrien).getContent());
        }

        sumOfNutrientI.put(nutrien, sumOfNutrientContent);
    }
    return sumOfNutrientI;

}

private Set<String> getnutrients(Ingredients choosenIngredients) {

    Set<String> nutrients = new HashSet<>();

    for (int i = 0; i < choosenIngredients.getIngredients().size(); i++) {

        Ingredient ingredient = choosenIngredients.getIngredients().get(i);
        for (int j = 0; j < ingredient.getNutrients().size(); j++) {
            nutrients.add(ingredient.getNutrients().get(j).getNutrientName());
        }
    }

    return nutrients;
}

createVariables方法评估了n次,其中n =种群大小。下面的代码用于生成实数。

public class RealCustom extends Variable {

    private double value_;
    private double lowerBound_;
    private double upperBound_;

    public RealCustom(Random random, double lowerBound, double upperBound) {
        lowerBound_ = lowerBound;
        upperBound_ = upperBound;
        value_ = (random.nextInt((int) ((upperBound - lowerBound) * 10 + 1)) + (lowerBound * 10)) / 10.0;
    }

    public RealCustom(double lowerBound, double upperBound, double value) {
        lowerBound_ = lowerBound;
        upperBound_ = upperBound;
        value_ = value;
    }

    public double getValue() {
        return value_;
    }

    public void setValue(double value) {
        value_ = value;
    }

    ....
    ....
}

我需要快速生成初始人口。但是使用这些代码,群体生成需要花费太多时间,因为新的生成的染色体/变量不会被放入群体中,直到所有营养素需要满足createVariables方法确认。

我不认为这个问题是由MOOP(CMIIW)的设计引起的。我想到的是我必须使用并发或多线程来加快人口生成,但我对此表示怀疑。那么有什么建议吗?。

1 个答案:

答案 0 :(得分:0)

我在控制声明中犯了一个错误,导致人口生成变慢。

<?php
$myString = $_POST['data'];

if ($myString == "") {
    echo json_encode(
      array()
      );

} else if ($myString == "foo" {
    echo json_encode(
      array(
        'foo2' => 'this is the contents of foo'
        )
      );
} else if ($myString == "foo2") {
    echo json_encode(
      array(
        'foo2' => 'this is the contents of foo2'
        )
      );
}
?>


<script>
  var formData = new FormData($(this)[0]);
  $.ajax({
    url: $(this).attr("action"),
    context: document.body,
    data: formData, 
    type: "POST",  
    contentType: false,
    processData: false,
    success: function(response) {
      if (response.length == 0) {
          alert("empty");
      } else if (response.foo) {          
          alert("foo");
      } else if (respons.foo2) {
          alert("foo2");
      }          
    }
  });           
</script>

应该是

// if nutrient (key) need has min and max limit
if (nutrientNeeds.getNutrientNeed(key).getMax() != 0) {
     if ((sumOfNutrientI.get(key) > 
          ...
     } 
}