遗传算法 - 部分映射交叉 - Java

时间:2016-11-02 22:08:49

标签: java arrays sorting while-loop genetic-algorithm

我正在开发一些非常有趣的东西,遗传算法中的TSP,更具体地说是部分映射的交叉。对于代码的背景,它接收两个int类型的数组,它们对应于相关的城市,例如,第一个和第二个可以是1,2,3,4,5,6,7和2,3,4,5, 2,4,3。接下来发生的事情是我尝试跨越城市而没有任何重复,但是当我执行while循环时,它似乎无法解决我的问题,因为它陷入无限循环。

基本上,我很困惑,为什么它会陷入循环,最终它应该越过城市并摆脱所有重复,但由于某种原因,我永远陷入困境! / p>

代码背景: SIZE =数组中的城市大小,父级和父级2包含大小为SIZE的随机城市。

任何帮助都会大大降低!

private int[][] partiallyMappedCrossover(int first, int second){
    //Used to return an array of type int
    int[][] tempArray = new int[2][SIZE];
    //Used to represent the selected individuals
    ArrayList<Integer> parentOne = new ArrayList<Integer>();
    ArrayList<Integer> parentTwo = new ArrayList<Integer>();
    ArrayList<Integer> parentOneExchange = new ArrayList<Integer>();
    ArrayList<Integer> parentTwoExchange = new ArrayList<Integer>();
    //Used to generate crossOverPoints
    ArrayList<Integer> crossOverPoints = new ArrayList<Integer>();
    crossOverPoints.add(random.nextInt(SIZE));
    crossOverPoints.add(random.nextInt(SIZE));
    Collections.sort(crossOverPoints);
    //Used for checking the parents contents
    int currentCity = 0;
    int arrayIndex = 0;
    int newCity = 0;

    //Assign the contents of the selected parents to my parentArrays
    for(int i = 0; i < SIZE; i++){
        parentOne.add(population[first][i]);
        parentTwo.add(population[second][i]);
    }
    //used to gather cities from tours and swap between randomly selected crossoverpoints
    for(int k = crossOverPoints.get(0) ; k < crossOverPoints.get(1) ; k++){
        //declare ints to store the city value
        int a = parentOne.get(k);
        int b = parentTwo.get(k);
        //excahnge cities between the two crossOverPoints
        parentOneExchange.add(b); 
        parentTwoExchange.add(a);
    }

    for(int i = 0; i < crossOverPoints.get(0); i++){
        //get the first city from the parentOne
        currentCity = parentOne.get(i);
        //Check the cities
        if(parentOneExchange.contains(currentCity)){
            //If it does contain the city, give one the index from the exchange
            arrayIndex = parentOneExchange.indexOf(currentCity);
            // get the city where we have a repitition
            newCity = parentTwo.get(arrayIndex);
            //if the new city is also a duplicated one, do another check
            while(parentOneExchange.contains(newCity)){
                // get the index of the city to replace the repeated city
                arrayIndex = parentOneExchange.indexOf(newCity);
                // get the city that is intended to replace the repeated city
                newCity = parentTwo.get(arrayIndex);
            }
            //replace the duplicated city with the new city
            parentOne.set(i,newCity);
        }
        currentCity = parentTwo.get(i);
        if(parentTwoExchange.contains(currentCity)){
            //If it does contain the city, give one the index from the exchange
            arrayIndex = parentTwoExchange.indexOf(currentCity);
            // get the city where we have a repitition
            newCity = parentOne.get(arrayIndex);
            //if the new city is also a duplicated one, do another check
            while(parentTwoExchange.contains(newCity)){
                // get the index of the city to replace the repeated city
                arrayIndex = parentTwoExchange.indexOf(newCity);
                // get the city that is intended to replace the repeated city
                newCity = parentOne.get(arrayIndex);
            }
            //replace the duplicated city with the new city
            parentTwo.set(i,newCity);
        }
    }

    //loop the second crosschange
    for(int i = crossOverPoints.get(1); i < SIZE; i++){
        //get the first city from the parentOne
        currentCity = parentOne.get(i);
        //Check the cities
        if(parentOneExchange.contains(currentCity)){
            //If it does contain the city, give one the index from the exchange
            arrayIndex = parentOneExchange.indexOf(currentCity);
            // get the city where we have a repitition
            newCity = parentTwo.get(arrayIndex);
            //if the new city is also a duplicated one, do another check            
            while(parentOneExchange.contains(newCity)){
                // get the index of the city to replace the repeated city
                arrayIndex = parentOneExchange.indexOf(newCity);
                // get the city that is intended to replace the repeated city
                newCity = parentTwo.get(arrayIndex);
            }
            //replace the duplicated city with the new city
            parentOne.set(i,newCity);
        }
        currentCity = parentTwo.get(i);
        if(parentTwoExchange.contains(currentCity)){
            //If it does contain the city, give one the index from the exchange
            arrayIndex = parentTwoExchange.indexOf(currentCity);
            // get the city where we have a repitition
            newCity = parentOne.get(arrayIndex);
            //if the new city is also a duplicated one, do another check
            while(parentTwoExchange.contains(newCity)){
                // get the index of the city to replace the repeated city
                arrayIndex = parentTwoExchange.indexOf(newCity);
                // get the city that is intended to replace the repeated city
                newCity = parentOne.get(arrayIndex);
            }
            //replace the duplicated city with the new city
            parentTwo.set(i,newCity);                
        }
    }
    //Assign the new offspring to the temp array for return
    for(int i = 0; i<SIZE; i++){
        tempArray[0][i] = parentOne.get(i);
        tempArray[1][i] = parentTwo.get(i);
    }
    //return the contents of my tempArray
    return tempArray;
}

1 个答案:

答案 0 :(得分:1)

阅读代码以找到这样的错误是非常困难和费力的。有很多简单的方法可以找到这些类型的错误。我会给你四个考虑(按照我粗略的偏好顺序):

  1. 将方法中的各种操作拆分为单独的方法,然后为每个方法编写单元测试,确保它们在移动到下一个方法之前完全符合您的预期。一旦它们全部工作,那么你编写一个使用它们的方法。调试一个小方法要比调试一个大方法容易得多。

  2. 添加assert语句,检查您期望为真的条件实际上是否为真。我将在下面给出一个例子。

  3. 交互式调试器可以找到循环未完成的原因。这样,您就可以确切地看到变量在循环中的每个点处具有的值。

  4. 随着方法的进展,添加日志语句以记录临时值。这样可以确保在算法进行时满足预期条件。

  5. 查看你的一个while循环:

    while(parentOneExchange.contains(newCity)){
        // get the index of the city to replace the repeated city
        arrayIndex = parentOneExchange.indexOf(newCity);
        // get the city that is intended to replace the repeated city
        newCity = parentTwo.get(arrayIndex);
    }
    

    这将在任何时候parentTwo.get返回之前遇到过的城市时无限循环。我希望这是由于代码中早期的逻辑错误而发生的事情。您可以添加断言以确保不是这种情况:

    List<Integer> previous = new ArrayList<>();
    while(parentOneExchange.contains(newCity)){
        assert !previous.contains(newCity): previous;
        previous.add(newCity);
        arrayIndex = parentOneExchange.indexOf(newCity);
        newCity = parentTwo.get(arrayIndex);
    }
    

    当这个断言失败时,您可以看到以前访问过的城市的列表,并尝试理解它为什么循环。