如何更快地生成约束多目标优化中的初始种群
How to generate initial population in constrained multiobjective optimization faster
我使用 NSGA-II 来解决受约束的 MOOP、饲料配方问题。在初始化步骤中,我总是在接受并放入种群之前验证生成的随机染色体是否需要约束。但是这一步需要的时间比较长,大约需要24小时。
如果我没有验证染色体,给出的解不满足约束条件。大多数解决方案仅满足 8 的 1 - 2 营养限制。
在这种情况下,如何快速生成初始种群?
// 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;
}
....
....
}
我需要快速生成初始种群。但是使用这些代码,人口生成需要太多时间,因为新生成的 chromosome/variables 将不会被放入人口中,直到所有营养需求都满足 createVariables
方法中确认。
我不认为这个问题是由MOOP(CMIIW)的设计引起的。我想到的是我必须使用并发或多线程来加快人口生成速度,但我对此表示怀疑。那么有什么建议吗?
我在控制语句中犯了一个错误,导致种群生成速度变慢。
// if nutrient (key) need has min and max limit
if (nutrientNeeds.getNutrientNeed(key).getMax() != 0) {
if ((sumOfNutrientI.get(key) >
...
}
}
应该是
if (nutrientNeeds.getNutrientNeed(key).getMax() != Double.POSITIVE_INFINITY) {
if ((sumOfNutrientI.get(key) >
...
}
}
我使用 NSGA-II 来解决受约束的 MOOP、饲料配方问题。在初始化步骤中,我总是在接受并放入种群之前验证生成的随机染色体是否需要约束。但是这一步需要的时间比较长,大约需要24小时。
如果我没有验证染色体,给出的解不满足约束条件。大多数解决方案仅满足 8 的 1 - 2 营养限制。
在这种情况下,如何快速生成初始种群?
// 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;
}
....
....
}
我需要快速生成初始种群。但是使用这些代码,人口生成需要太多时间,因为新生成的 chromosome/variables 将不会被放入人口中,直到所有营养需求都满足 createVariables
方法中确认。
我不认为这个问题是由MOOP(CMIIW)的设计引起的。我想到的是我必须使用并发或多线程来加快人口生成速度,但我对此表示怀疑。那么有什么建议吗?
我在控制语句中犯了一个错误,导致种群生成速度变慢。
// if nutrient (key) need has min and max limit
if (nutrientNeeds.getNutrientNeed(key).getMax() != 0) {
if ((sumOfNutrientI.get(key) >
...
}
}
应该是
if (nutrientNeeds.getNutrientNeed(key).getMax() != Double.POSITIVE_INFINITY) {
if ((sumOfNutrientI.get(key) >
...
}
}