Я реализую классический генетический алгоритм. В фазе кроссовера я нахожу странное поведение.Почему List <T> .RemoveRange (индекс, счет) изменяет значение перед индексом?
private static void Crossover(ref List<CrossoverPair> pairs)
{
var random = new Random();
//TODO debug this
foreach (var pair in pairs)
{
for (var i = 0; i < pair.First.Chromosomes.Count; i++)
{
var locus = random.Next(1, 12);
var crossoverLength = pair.First.Chromosomes[i].Genes.Count - locus;
var swapFirst = pair.First.Chromosomes[i].Genes.Skip(locus).Take(crossoverLength).ToList();
var swapSecond = pair.Second.Chromosomes[i].Genes.Skip(locus).Take(crossoverLength).ToList();
pair.First.Chromosomes[i].Genes.RemoveRange(locus - 1, crossoverLength);
pair.First.Chromosomes[i].Genes.AddRange(swapSecond);
pair.Second.Chromosomes[i].Genes.RemoveRange(locus - 1, crossoverLength);
pair.Second.Chromosomes[i].Genes.AddRange(swapFirst);
}
}
}
Каждая хромосома содержит 12 генов. Он заменяет гомологичные части, начиная с случайно определенного локуса. Например, если у нас locus = 8
и crossoverLength = 4
, мы сначала удаляем гены от Genes[8]
до Genes[11]
с использованием RemoveRange
, затем добавляем гены из другой хромосомы с использованием AddRange
.
Иногда случается что-то странное: когда мы используем RemoveRange
, Genes[7]
(для этого экземпляра) меняет свое значение от 0 до 1 или от 1 до 0. Это не происходит на каждой итерации, иногда все работает нормально. Я заметил, что это происходит чаще всего для locus = 7..11
.
Это не слишком сильно вредит алгоритму (просто больше мутаций: D). Но кто-нибудь знает, почему он инвертирует ценности?
Update:
Большого спасибо BJ Myers для исчерпывающего ответа. Все, кто прочитает это сообщение позже, могут быть заинтересованы, почему это происходит. Это объясняется хорошим here.