2016-10-23 3 views
0

저는 고전적인 유전자 알고리즘을 구현하고 있습니다. 크로스 오버 단계에서 나는 이상한 행동을 찾고있다.Why List <T> .RemoveRange (index, count)는 인덱스 이전의 값을 변경합니까?

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 = 8crossoverLength = 4이있는 경우 먼저 Genes[8]에서 Genes[11]까지 유전자를 제거하고 RemoveRange을 사용하고 AddRange을 사용하여 다른 염색체의 유전자를 추가합니다.

때로는 이상한 일이 발생합니다. RemoveRange을 사용하면 Genes[7] (이 인스턴스의 경우) 값이 0에서 1 또는 1에서 0으로 변경됩니다. 각 반복마다 발생하지는 않지만 때로는 모든 것이 정상적으로 작동합니다. 나는 그것이 더 자주 locus = 7..11에 대해 발생하는 것으로 나타났습니다.

알고리즘을 너무 많이 손상시키지 않습니다 (단지 더 많은 돌연변이가 있습니다 : D). 하지만 왜 사람들이 가치를 왜곡하는지 아는 사람이 있습니까?

Strange behaviour proof

업데이트 :

감사 논박 할 수없는 답변 BJ 마이어스에 많은. 나중에이 게시물을 읽는 모든 사람들이 관심을 가질 것입니다. 왜 그렇게됩니까? 그것은 좋은 here 설명되어 있습니다.

답변

2

RemoveRange은 지정된 인덱스 이전의 값을 변경하지 않습니다. 그것이 나타나는 이유는 색인이 하나만 존재하기 때문입니다.

이 줄에서보세요 : 우리가 가정하면

pair.First.Chromosomes[i].Genes.RemoveRange(locus - 1, crossoverLength); 

locus = 8 따라서 crossoverLength = 4 (당신의 예에서와 같이), 원하는 동작이 [11]을 통해 인덱스 [8]와 요소를 제거하는 것입니다. 그러나 locus에서 1을 뺀 것이므로 의 첫 번째 매개 변수로 7을 전달하므로 [7]에서 [10]까지 요소가 제거됩니다. 소자 [7] 변화가 실제로 [10] 통해 [7] 제거되는 요소의 결과였다 것처럼 인식

pair.First.Chromosomes[i].Genes.RemoveRange(locus, crossoverLength); 

동작하며 :

올바른 코드가 - 1 통화 중 오프셋 RemoveRange에 포함되지 않아야 이전에 [11]에 있었던 요소는 [7] 위치로 이동합니다. "유전자"가 항상 바이너리라면 RemoveRange 호출의 결과로 값이 "변경"될 가능성이 50/50입니다.

관련 문제