本文已参与【新人创作礼】活动,一起开启掘金创作之路
MTO Jmetal IGD计算BUG
觉得有用的话,欢迎一起讨论相互学习~
- 大家知道只要有种群的目标函数值和PF前沿,按道理将是可以计算IGD的
错误分析
- 遇到以下错误:
- 追踪错误后发现,错误来源于:
- 这里的front[i]越界了,在MTO中,计算IGD时,max和min应该是target任务的obj维度,而不是总的维度。 举例,一般情况下MTO中一个任务的IGD根据skillfactor的不同应该是inf,inf,0.1,0.1这种,所以是四维的。但是单个问题的PF其实是2维的或者3维的,也就是说min和max都是二维和三维的因此,当j迭代到2的时候,但是maxmumvalue数组的最大索引是1,所以这个时候会出现数组的越界。
证实猜想
- 经过单步调试,可以看见front[i]的维度是4,max和min的维度都是2,这样j到2时,表示遍历第三个维度,就会越界!
- 这是因为在初始化solution时,我们使用的是Problemset,这个参数默认的是统一空间的维度,即问题的最大维度
Solution sol = new Solution(problemSet); - 这种方式是initialize 种群的时候是可取的,但是计算IGD时是不可取的。
解决方案
- 可以通过departpopulation()函数按照skillfactor将种群重新分成两组,并且每组的obj的数目和其skillfactor的保持一致。
//用于将整个大种群划分为分配给不同任务的子种群
void departpopulation() {
// resPopulation 是一个Solution的集合数组
resPopulation = new SolutionSet[problemSet_.size()];
for (int i = 0; i < problemSet_.size(); i++)
resPopulation[i] = new SolutionSet();
for (int i = 0; i < population.size(); i++) {
// 因为优化后后的种群中每个个体有一个Skill_factors,必须要将每个个体按照其skill_factor分类
Solution sol = population.get(i);
int pid = sol.getSkillFactor();
//start 和 end 时目标函数在Problemset中的索引
int start = problemSet_.get(pid).getStartObjPos();
int end = problemSet_.get(pid).getEndObjPos();
Solution newSolution = new Solution(end - start + 1);
for (int k = start; k <= end; k++) {
//复制个体目标值
newSolution.setObjective(k - start, sol.getObjective(k));
//别忘了复制个体决策变量函数值
newSolution.setDecisionVariables(sol.getDecisionVariables());
}
resPopulation[pid].add(newSolution);
}
}
- 特别注意其中new solution 时候的方式
Solution newSolution = new Solution(end - start + 1);,以及对目标进行赋值时的方式,只根据特定任务赋值,newSolution.setObjective(k - start, sol.getObjective(k)),因此此时其目标函数是end-start+1,而不是统一空间的4. - 下图是此解决方案用于三目标问题时的调试结果
- 证明提出的方法可以解决这个问题!
最终代码
- 最终,我们的IGD代码修改为:
void getIGD(SolutionSet pop) {
SolutionSet resPopulation = new SolutionSet();
for (int i = 0; i < pop.size(); i++) {
Solution sol = pop.get(i);
int pid = sol.getSkillFactor();
//start 和 end 时目标函数在Problemset中的索引
int start = problemSet.get(pid).getStartObjPos();
int end = problemSet.get(pid).getEndObjPos();
//最关键的是这里,需要对目标值修改为当前任务目标个数
//否则会出bug,因为统一空间的目标个数是一定的
Solution newSolution = new Solution(end - start + 1);//
for (int k = start; k <= end; k++) {
//复制个体目标值
newSolution.setObjective(k - start, sol.getObjective(k));
//别忘了复制个体决策变量函数值
newSolution.setDecisionVariables(sol.getDecisionVariables());
}
resPopulation.add(newSolution);
}
String pf1 = "PF/" + problemSet.get(1).getHType() + ".pf";
QualityIndicator indicator1 = new QualityIndicator(problemSet.get(1), pf1);
double igd1 = indicator1.getIGD(resPopulation);
System.out.println("IGD" + form.format(igd1));
}