遺傳算法庫(kù)jmetal最簡(jiǎn)示例
這個(gè)示例展示了如何使用 JMetal 進(jìn)行簡(jiǎn)單的多目標(biāo)優(yōu)化問(wèn)題。你可以根據(jù)需要修改問(wèn)題、算法參數(shù)和算子來(lái)適應(yīng)不同的優(yōu)化問(wèn)題。
遺傳算法的簡(jiǎn)單處理流程
摘自 https://pymoo.org/algorithms/soo/ga.html
https://github.com/Mycenae/PaperWeekly/blob/master/jMetalPy.md

NSGAII 算法特點(diǎn):
- 種群大小保持一致:在 NSGA-II 中,父代種群和子代種群的大小是相同的。如果初始種群包含?? 個(gè)個(gè)體,那么在每一代中,子代的數(shù)量也將是 ??。
- 選擇機(jī)制:在合并的種群中(父代和子代的組合),算法根據(jù)非支配等級(jí)和擁擠度距離選擇出 ?? 個(gè)個(gè)體作為下一代的種群。因此,最終的可行解個(gè)數(shù)不會(huì)超過(guò)初始種群的個(gè)體數(shù)。
- 多目標(biāo)優(yōu)化:盡管最終的可行解個(gè)數(shù)最多為 ??,但 NSGA-II 的目標(biāo)是找到多個(gè) Pareto 最優(yōu)解,最終返回的解可能在目標(biāo)空間中形成一個(gè) Pareto 前沿。
NSGAIII 算法特點(diǎn):
- NSGAII 因?yàn)槭褂梅侵渑判蚝蛽頂D度距離來(lái)選擇個(gè)體, 當(dāng)目標(biāo)函數(shù)數(shù)量較多時(shí)候, 計(jì)算效率會(huì)變差.
- NSGAIII 的優(yōu)勢(shì)主要體現(xiàn)在目標(biāo)函數(shù)較多的情況下, 它使用均勻分布的參考點(diǎn)來(lái)引導(dǎo)個(gè)體的選擇, 能更加有效覆蓋Pareto前沿, 解的多樣性會(huì)更好, 速度更快, 尤其是在高維目標(biāo)(即多目標(biāo)函數(shù))
相關(guān)類庫(kù)
- jmetal-algorithm :包含各種遺傳算法和算法執(zhí)行Main函數(shù)代碼,
- jmetal-core : 包含各種基礎(chǔ)類
- jmetal-problem : 定義了 AbstractDoubleProblem 和 AbstractIntegerProblem 問(wèn)題域抽象, 也定義了很多常用的問(wèn)題模型, 比如 ZDT1 性能測(cè)試用問(wèn)題, 比如 Traveling Salesman Problem 等.
- jmetal-lab: 可選包, 包含作者的一些學(xué)習(xí)和測(cè)試代碼, 我們可以借鑒一下.
編程提示:
- 問(wèn)題定義示例可以參考 ZDT1
- 求解器主函數(shù)可以參考 NSGAIIRunner
- NSGAII 算法是按照最小值做優(yōu)化的, 所以如果要求最大值, objective 函數(shù)要乘負(fù)一.
- 在新版6.6中, 貌似沒(méi)找到算法迭代 Observer, 這樣對(duì)于觀察每代的情況不是很方便, Problem 的 evaluate() 會(huì)對(duì)個(gè)體評(píng)價(jià), 可以很容易訪問(wèn)到的決策變量變量(即基因)和objective(即適應(yīng)度), 所以可以在這個(gè)方法中加上日志來(lái)觀察演進(jìn)變化.
關(guān)于約束問(wèn)題
- 需要說(shuō)明的是, 所有的遺傳算法都是隨機(jī)搜索算法,可能會(huì)生成不滿足約束的解, 對(duì)于多目標(biāo)函數(shù)尤為如此.
- NSGAII/SPEA2 , 尤其是在解決無(wú)約束多目標(biāo)優(yōu)化問(wèn)題的性能而被廣泛使用, 對(duì)于約束, 這些算法底層使用了懲罰函數(shù)來(lái)柔性評(píng)估約束, 這種方法并不能保證生成的解一定滿足約束, 只是使得滿足約束的解有更大可能被選擇.
- 推薦使用BinaryTournamentSelection 選擇算子, 它實(shí)現(xiàn)"feasibility rule"的一種選擇操作。BinaryTournamentSelection在選擇操作中,會(huì)隨機(jī)選擇兩個(gè)解進(jìn)行比較,如果兩個(gè)解在Pareto支配關(guān)系中可以比較,那么就選擇支配對(duì)方的解;如果兩個(gè)解在Pareto支配關(guān)系中無(wú)法比較,那么就選擇滿足約束的解;如果兩個(gè)解都滿足約束,或者都不滿足約束,那么就隨機(jī)選擇一個(gè)解。 但是,需要注意的是,即使使用了"feasibility rule",也不能保證所有的解都滿足約束,因?yàn)檫z傳算法是一種隨機(jī)搜索算法,可能會(huì)生成不滿足約束的解.
- 在代碼中可通過(guò)設(shè)置 solution.constraints()[i] 取值來(lái)設(shè)定約束條件, 即給出懲罰值, 取值>=0為滿足約束, 取值小于0為違反約束. 針對(duì)違法約束, 不要設(shè)置成固定的懲罰值, 應(yīng)該按照遠(yuǎn)離約束條件的程度來(lái)設(shè)定懲罰值, 這樣后代才有可能進(jìn)化; 滿足約束, 可以直接設(shè)定一個(gè)定值.
- 為了保證結(jié)果一定滿足約束, 方法有:
. 可以在算法結(jié)果solutionSet中過(guò)濾掉哪些不符合約束的solution
. 在將約束條件轉(zhuǎn)換成目標(biāo)函數(shù).
. 對(duì)于違反約束的情況, 可在Problem 的 evaluate() 方法中, 主動(dòng)設(shè)置 objective 為一個(gè)較差的結(jié)果.
代碼解釋:
- 定義問(wèn)題:可以直接使用內(nèi)置的 ZDT1 問(wèn)題,它是一個(gè)經(jīng)典的雙目標(biāo)優(yōu)化問(wèn)題, 我也自定義了兩個(gè)簡(jiǎn)單的問(wèn)題。
- 定義算法:使用 NSGA-II 算法,并設(shè)置種群大小和迭代次數(shù)。
- 設(shè)置交叉和變異算子:這里使用 SBX 交叉和多項(xiàng)式變異。
- 設(shè)置選擇算子:使用二進(jìn)制錦標(biāo)賽選擇。
- 運(yùn)行算法:執(zhí)行算法并記錄執(zhí)行時(shí)間。
- 打印結(jié)果:打印每個(gè)解的詳細(xì)信息。
- 輸出結(jié)果到文件:將結(jié)果輸出到文件中。
package aaaaaaa;
import java.util.ArrayList;
import java.util.List;
import org.uma.jmetal.algorithm.Algorithm;
import org.uma.jmetal.algorithm.examples.AlgorithmRunner;
import org.uma.jmetal.algorithm.multiobjective.nsgaii.NSGAIIBuilder;
import org.uma.jmetal.operator.crossover.CrossoverOperator;
import org.uma.jmetal.operator.crossover.impl.SBXCrossover;
import org.uma.jmetal.operator.mutation.MutationOperator;
import org.uma.jmetal.operator.mutation.impl.PolynomialMutation;
import org.uma.jmetal.operator.selection.SelectionOperator;
import org.uma.jmetal.operator.selection.impl.BinaryTournamentSelection;
import org.uma.jmetal.problem.Problem;
import org.uma.jmetal.problem.doubleproblem.impl.AbstractDoubleProblem;
import org.uma.jmetal.problem.multiobjective.zdt.ZDT1;
import org.uma.jmetal.solution.doublesolution.DoubleSolution;
import org.uma.jmetal.util.AbstractAlgorithmRunner;
import org.uma.jmetal.util.ConstraintHandling;
import org.uma.jmetal.util.JMetalLogger;
import org.uma.jmetal.util.comparator.RankingAndCrowdingDistanceComparator;
import org.uma.jmetal.util.fileoutput.SolutionListOutput;
import org.uma.jmetal.util.fileoutput.impl.DefaultFileOutputContext;
public class App {
public static void main(String[] args) {
// 1. 定義問(wèn)題
Problem<DoubleSolution> problem = null;
problem = new ZDT1();
problem = new TwoObjectiveProblem();
problem = new PortfolioProblem();
problem = new SquareDistanceProblem();
// 2. 設(shè)置交叉和變異算子 和 設(shè)置選擇算子
// 定義交叉操作: SBX交叉
double crossoverProbability = 0.9;
double crossoverDistributionIndex = 20.0;
CrossoverOperator<DoubleSolution> crossover = new SBXCrossover(crossoverProbability,
crossoverDistributionIndex);
// 定義變異操作: 多項(xiàng)式變異
double mutationProbability = 1.0 / problem.numberOfVariables();
double mutationDistributionIndex = 20.0;
MutationOperator<DoubleSolution> mutation = new PolynomialMutation(mutationProbability,
mutationDistributionIndex);
// 定義選擇操作: 二元競(jìng)標(biāo)賽選擇
SelectionOperator<List<DoubleSolution>, DoubleSolution> selection = new BinaryTournamentSelection<>(
new RankingAndCrowdingDistanceComparator<>());
// 3. 迭代次數(shù)和種群大小
int populationSize = 100;
// 4. 定義算法(NSGA-II)
// Algorithm<List<DoubleSolution>> algorithm = new NSGAIIBuilder<>(problem, crossover, mutation, populationSize)
// .setSelectionOperator(selection).setMaxEvaluations(25000).build();
Algorithm<List<DoubleSolution>> algorithm = new NSGAIIBuilder<>(problem, crossover, mutation, populationSize)
.setSelectionOperator(selection).setMaxEvaluations(25000).build();
// 5. 運(yùn)行算法
AlgorithmRunner algorithmRunner = new AlgorithmRunner.Executor(algorithm).execute();
List<DoubleSolution> solutionSet = algorithm.result();
long computingTime = algorithmRunner.getComputingTime();
JMetalLogger.logger.info("Total execution time: " + computingTime + "ms");
// 6. 打印非支配排序結(jié)果,每個(gè)solution包含決策變量取值和目標(biāo)函數(shù)取值.
for (DoubleSolution solution : solutionSet) {
JMetalLogger.logger.info("Solution: " + solution);
}
JMetalLogger.logger.info("Solution Count: " + solutionSet.size());
// 7. save to tsv files
new SolutionListOutput(solutionSet).setVarFileOutputContext(new DefaultFileOutputContext("VAR.csv", ","))
.setFunFileOutputContext(new DefaultFileOutputContext("FUN.csv", ",")).print();
AbstractAlgorithmRunner.printFinalSolutionSet(solutionSet);
}
}
/*
* 演示單目標(biāo)函數(shù), 多決策變量, 另外帶有約束條件處理過(guò)程
*
*/
class SquareDistanceProblem extends AbstractDoubleProblem {
private int generationCount;
public SquareDistanceProblem() {
name("SquareDistance Problem");
numberOfObjectives(1); // 設(shè)置目標(biāo)函數(shù)數(shù)量
numberOfConstraints(2);// 設(shè)置約束條件數(shù)量
double maxWidth = 998;
double maxHeight = 680;
Integer numberOfVariables = 4;
List<Double> lowerLimit = new ArrayList<>(numberOfVariables);
List<Double> upperLimit = new ArrayList<>(numberOfVariables);
// x1
lowerLimit.add(0.0);
upperLimit.add(maxWidth);
// y1
lowerLimit.add(0.0);
upperLimit.add(maxHeight);
// x2
lowerLimit.add(0.0);
upperLimit.add(maxWidth);
// y2
lowerLimit.add(0.0);
upperLimit.add(maxHeight);
variableBounds(lowerLimit, upperLimit);
}
/** Evaluate() method */
public DoubleSolution evaluate(DoubleSolution solution) {
generationCount = generationCount + 1;
System.out.println("Generation: " + generationCount);
double x1 = solution.variables().get(0);
double y1 = solution.variables().get(1);
double x2 = solution.variables().get(2);
double y2 = solution.variables().get(3);
double distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
double objective = -1 * distance;
solution.objectives()[0] = objective;
evaluateConstraints(solution);
System.out.println("Feasible: " + ConstraintHandling.isFeasible(solution));
// 當(dāng)約束不滿足時(shí)候, 調(diào)整objective為較差的值, 這樣遺傳算法為拋棄這一后代
if (ConstraintHandling.isFeasible(solution) == false) {
solution.objectives()[0] = 1000;
}
return solution;
}
/** EvaluateConstraints() method */
public void evaluateConstraints(DoubleSolution solution) {
JMetalLogger.logger.info("evaluateConstraints");
double x1 = solution.variables().get(0);
double y1 = solution.variables().get(1);
double x2 = solution.variables().get(2);
double y2 = solution.variables().get(3);
// https://jmetal.readthedocs.io/en/latest/constraints.html
double contraintX = x1 - x2; // 約束條件為x1-x2>=0, 如果<0被認(rèn)為違反約束
solution.constraints()[0] = contraintX;// ;contraintX
double contraintY = y1 - y2; // 約束條件為y1-y2>=0, 如果<0被認(rèn)為違反約束
solution.constraints()[1] = contraintY;// contraintY;
}
}
/*
* 定義兩個(gè)目標(biāo)函數(shù)的示例 單決策變量, 該優(yōu)化會(huì)有很多個(gè)解
*/
class TwoObjectiveProblem extends AbstractDoubleProblem {
private int generationCount;
public TwoObjectiveProblem() {
name("TwoObjectiveProblem");
numberOfObjectives(2);// 設(shè)置目標(biāo)函數(shù)數(shù)量
numberOfConstraints(2);// 設(shè)置約束條件數(shù)量
// Set variable bounds
List<Double> lowerLimit = new ArrayList<>();
lowerLimit.add(-5.0);
List<Double> upperLimit = new ArrayList<>();
upperLimit.add(5.0);
variableBounds(lowerLimit, upperLimit);
}
public DoubleSolution evaluate(DoubleSolution solution) {
generationCount = generationCount + 1;
System.out.println("Generation: " + generationCount);
double x = solution.variables().get(0);
solution.objectives()[0] = x * x; // f1 = x^2
solution.objectives()[1] = (x - 2) * (x - 2); // f2 = (x - 2)^2
evaluateConstraints(solution);
System.out.println("Feasible: " + ConstraintHandling.isFeasible(solution));
return solution;
}
/** EvaluateConstraints() method */
public void evaluateConstraints(DoubleSolution solution) {
JMetalLogger.logger.info("evaluateConstraints");
double x = solution.variables().get(0);
// https://jmetal.readthedocs.io/en/latest/constraints.html
// 設(shè)置約束條件為 1.5>x>1
double contraintX = -1;
if (x > 1 && x < 1.5) {
contraintX = 1; // OK
} else if (x <= 1) {
contraintX = -1 * (1 - x); // 懲罰
} else {
contraintX = -1 * (x - 1.5); // 懲罰
}
solution.constraints()[0] = contraintX;
}
}
/*
* 假設(shè)了三個(gè)資產(chǎn)的預(yù)期收益率分別為5%,7%,9%, 風(fēng)險(xiǎn)分別為1%,2%,3%。 在實(shí)際應(yīng)用中,這些值通常需要從歷史數(shù)據(jù)中計(jì)算得出。
*/
class PortfolioProblem extends AbstractDoubleProblem {
public PortfolioProblem() {
numberOfObjectives(2); // Minimize risk and maximize return
numberOfConstraints(1);
// Set variable bounds
// 3 stock share, 決策變量為它們?cè)谕顿Y組合中的占比
List<Double> lowerLimit = new ArrayList<>();
lowerLimit.add(0.0);
lowerLimit.add(0.0);
lowerLimit.add(0.0);
List<Double> upperLimit = new ArrayList<>();
upperLimit.add(1.0);
upperLimit.add(1.0);
upperLimit.add(1.0);
variableBounds(lowerLimit, upperLimit);
}
public DoubleSolution evaluate(DoubleSolution solution) {
double[] x = new double[solution.variables().size()];
double sum = 0.0;
for (int i = 0; i < solution.variables().size(); i++) {
x[i] = solution.variables().get(i);
sum += x[i];
}
// 約束處理: 將投資比例標(biāo)準(zhǔn)化, Add the constraint that the sum of the weights must be 1
// 這里沒(méi)有使用 solution.constraints() 來(lái)進(jìn)行約束限定, 因?yàn)閟olution.constraints()不是強(qiáng)制約束
// 所以在變量層面做了歸一化處理.
if (sum > 0) {
for (int i = 0; i < solution.variables().size(); i++) {
x[i] /= sum; // 標(biāo)準(zhǔn)化為比例
}
}
for (int i = 0; i < solution.variables().size(); i++) {
solution.variables().set(i, x[i]);
}
// Calculate the portfolio return and risk
// Example returns, 收益率分別為5%,7%,9%
double return_ = x[0] * 0.05 + x[1] * 0.07 + x[2] * 0.09;
// Example risks, 風(fēng)險(xiǎn)分別為1%,2%,3%
double risk_ = x[0] * 0.01 + x[1] * 0.02 + x[2] * 0.03;
// Set the objectives
solution.objectives()[0] = -1 * return_; // We want to maximize the return, so we minimize -return
solution.objectives()[1] = risk_; // We want to minimize the risk
if (sum != 1) {
solution.constraints()[0] = -100 * sum; // 懲罰
} else {
solution.constraints()[0] = 1; // OK
}
System.out.println("Feasible: " + ConstraintHandling.isFeasible(solution));
return solution;
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sss</groupId>
<artifactId>aaaaaaa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.uma.jmetal</groupId>
<artifactId>jmetal-core</artifactId>
<version>6.6</version>
</dependency>
<dependency>
<groupId>org.uma.jmetal</groupId>
<artifactId>jmetal-algorithm</artifactId>
<version>6.6</version>
</dependency>
<dependency>
<groupId>org.uma.jmetal</groupId>
<artifactId>jmetal-problem</artifactId>
<version>6.6</version>
</dependency>
<dependency>
<groupId>org.uma.jmetal</groupId>
<artifactId>jmetal-lab</artifactId>
<version>6.6</version>
</dependency>
</dependencies>
</project>

浙公網(wǎng)安備 33010602011771號(hào)