欢迎来到多目标优化领域。这是我写论文的一个领域。解决这类问题的算法有很多,但最著名的两种可能是 NSGA-II 和 SPEA2。
当然,您只有一个目标:无论您的评分函数是什么,都会产生影响。我认为多目标算法也适用,因为您不仅对单一解决方案感兴趣,而且对它们的总体感兴趣。
我可以给你指点http://jmetalnet.sourceforge.net/吗?
我们的想法是,您将生成包含输入的随机向量群体,这些输入范围跨越您的 100^6 个可能的解决方案的域。这些种群将发生突变并相互交配以产生新的解决方案,并从这些新种群中向下选择它们,以使更优选的解决方案被选择保留(并在进化过程中幸存下来)。
在多世界中,比较不同解决方案的适用性可能会遇到挑战。但是在你的单一目标世界中,比较适应度很容易:你只需要决定你想要更高的数字还是更低的数字。看来你想要更高。
概述
- 创建随机的解决方案群体。
- 在您的解决方案中随机变异/交叉。
- 计算每个人的健康状况并进行排序。
- 下采样回到最佳解决方案的初始总体规模。
- 重复步骤 2-4 [直到收敛:直到平均适应度 > 阈值?]
- 输出最后一代。
结果:
这是一个糟糕的分析,请注意,您可以通过在每个参数级别平均(例如)20 次运行的结果来做得更好。马上,您可以看出突变率应该保持在较低水平,显然,更大的种群规模会有所帮助(达到收敛点)。
结果格式为之前、之后的平均分,最高为 600
PopSize=100,NumGens=50,MutRate=0.2,CrossRate=0.8
295.23,542.12
PopSize=100,NumGens=500,MutRate=0.2,CrossRate=0.8
298.53,565
PopSize=1000,NumGens=50,MutRate=0.2,CrossRate=0.8
301.814,579.334
PopSize=10000,NumGens=500,MutRate=0.2,CrossRate=0.8
299.8901,588
PopSize=1000,NumGens=50,MutRate=0.4,CrossRate=0.8
306.22,385.55
代码
我在大约 20 分钟内编写了这段代码,所以它并不意味着优雅或出色。我希望它只是明白这一点。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace moo_in_csharp
{
internal class Individual
{
public int[] Decisions;
public double Fitness;
private int _numdecisions = 6;
/// <summary>
/// Default constructor.
/// </summary>
public Individual()
{
Decisions = new int[_numdecisions];
}
/// <summary>
/// Replaces first half of decisions with those of the mate.
/// </summary>
/// <param name="mate"></param>
public void Crossover(Individual mate)
{
int crossoverPoint = _numdecisions / 2;
for (int i = 0; i < crossoverPoint; i++)
{
Decisions[i] = mate.Decisions[i];
}
}
/// <summary>
/// Simple fitness function that computes sum of a+b+c+d+e+f.
/// </summary>
public double Evaluate()
{
Fitness = Decisions.Sum();
return Fitness;
}
/// <summary>
/// Assigns random values to its decisions.
/// </summary>
public void Generate()
{
for (int i = 0; i < _numdecisions; i++)
{
Decisions[i] = Program.rand.Next(0, 101);
}
}
/// <summary>
/// Randomly mutate select decisions.
/// </summary>
public void Mutate()
{
for (int i = 0; i < _numdecisions; i++)
{
Decisions[i] = Program.rand.Next(0, 101);
}
}
}
internal class Program
{
public static Random rand = new Random();
private static void Main(string[] args)
{
//parameters
int populationSize = 100;
int numGenerations = 50;
double mutationRate = 0.2;
double crossoverRate = 0.8;
//build initial population
List<Individual> solutions = new List<Individual>();
for (int i = 0; i < populationSize; i++)
{
var solution = new Individual();
solution.Generate();
solution.Evaluate();
solutions.Add(solution);
}
//calculate average score of initial population
var averageScoreBefore = solutions.Select(x => x.Evaluate()).Average();
//iterate across number of generations
for (int i = 0; i < numGenerations; i++)
{
//build offspring by mating sequential pairs of solutions
var offspring = new List<Individual>();
for (int e = 0; e < solutions.Count() - 1; e += 2)
{
if (rand.NextDouble() < crossoverRate)
{
var newIndividual = new Individual();
solutions[e].Decisions.CopyTo(newIndividual.Decisions, 0);
newIndividual.Crossover(solutions[e + 1]);
offspring.Add(newIndividual);
}
}
//add our offspring to our solutions
solutions.AddRange(offspring);
//mutate solutions at a low rate
foreach (var solution in solutions)
{
if (rand.NextDouble() < mutationRate)
{
solution.Mutate();
}
}
//sort our solutions and down-sample to initial population size
solutions = solutions.OrderByDescending(x => x.Evaluate()).ToList();
solutions = solutions.Take(populationSize).ToList();
}
//calculate average score after
var averageScoreAfter = solutions.Select(x => x.Evaluate()).Average();
Debug.WriteLine(averageScoreBefore + "," + averageScoreAfter);
}
}
}
其他说明
您的运行时间主要取决于您的健康评分功能。对于简单的数学函数,这个运行时并不难。显然,如果涉及到一个过程,您希望将评估次数保持在最低限度。这是我攻读博士学位时研究的,并开发了一种名为 GALE 的新算法: