Что здесь происходит с векторным массивом? - PullRequest
0 голосов
/ 02 июня 2019

Я решаю проблему коммивояжера с помощью реализации ACO в C ++.Однако я обнаружил, что созданная мною программа дает ошибку сегментации.(Примечание: я ограничил алгоритм только одной итерацией колонии для целей отладки).

Во-первых, у меня есть 52 города, взятых из файла, и я распределяю муравьев так, чтобыкаждый город имеет одинаковое количество муравьев, начиная с него.

Чтобы сохранить расстояния между каждой парой городов, я использую вектор векторов чисел с именем Map (квадратная матрица).Однако на полпути во время выполнения кажется, что эти векторы удалены.В данном случае это происходит при расчете пути для муравья № 55. Я добавил фрагмент кода, чтобы просто указать, где именно происходит сбой:

//DEBUGGING SECTION
                cout << "Size Roulette: " << Roulette.size() << endl;
                cout << "Size Remain: " << RemainingCities.size() << endl;
                cout << "Size Map: " << Map.size() << " x " << Map[0].size() << endl;

                int k = 0;
                cout << "Test: Map access: " << endl;
                for(int i = 0; i < Map.size(); ++i) //  HERE IT CRASHES AT ANT NUMBER 55
                    cout << Map[0][i] << " ";
                cout << endl;

                cout << "Test: Operation: " << Map[Colony[ant_i][city_i-1]][RemainingCities[k]] << endl;

                Roulette[k] = pow((MAX_DIST - Map[Colony[ant_i][city_i-1]][RemainingCities[k]]), heur_coef) + pow((pheromones[Colony[ant_i][city_i-1]][RemainingCities[k]]), pher_coef);

//END OF DEBUGGING SECTION

Там есть функция Map [0].size () обычно возвращает 52 (точно так же, как Map.size (), так как он должен быть квадратной матрицей), но при итерации сбоя он возвращает то, что выглядит как адрес памяти, и в тот момент, когда я пытаюсь получить доступ к любому элементу,возникает ошибка сегментации.

Я проверил, что доступ к памяти всегда правильный, и я могу получить доступ к любой другой переменной без проблем, кроме Map, до этого 55-го муравья.Я пробовал разные семена для метода рулетки, но он всегда вылетает в одном и том же месте.

Я также менял количество муравьев в колонии.Если это один муравей на город, программа выполняется без проблем, но при любом большем количестве программа всегда падает на 55 муравье.

Вы можете скачать полный файл cpp и чтение файла .tsp с github:

https://github.com/yitosmash/ACO

В любом случае я оставлю здесь полную функцию:

void ACO(const vector<City>& cities, const vector<vector<double>>& Map, int max_it, int num_ants, double decay, double heur_coef, double pher_coef, double pher_coef_elit)
{

        srand(30);

    //Initialise colony of ants (each ant is a vector of city indices)
    vector<vector<int>> Colony(num_ants, vector<int>(cities.size(), 0));

    //Initialise pheromone matrix
    vector<vector<double>> pheromones(cities.size(), vector<double>(cities.size(), 0));
    //Initialise costs vector(for etilist expansion)
    vector<double> costs(cities.size(), 0);

    //Auxiliar vector of indices
    vector<int> cityIndices(cities.size());
    for (int i = 0; i < cities.size(); ++i)
        cityIndices[i] = i;

    //Longest distance from Map, used for heuristic values.
    vector<double> longests(cities.size(), 0);
    for(int i = 0; i < cities.size(); ++i)
        longests[i] = *(max_element(Map[i].begin(), Map[i].end()));

    const double MAX_DIST = *(max_element(longests.begin(), longests.end()));
    longests.clear();


    int i=0;
    while(i<max_it)
    {
        for(int ant_i = 0; ant_i < num_ants; ++ant_i)
        {
            cout << "Ant: " << ant_i << endl;
            //City for ant_i to start at; each ant is assigned a determined starting city
            int starting_city = (int) ((float)ant_i/num_ants*cities.size());
            //cout << starting_city << endl;
            Colony[ant_i][0] = starting_city;

            //Get a vector with the cities left to visit
            vector<int> RemainingCities = cityIndices;

            //Remove starting city from remaining cities
            RemainingCities.erase(RemainingCities.begin() + starting_city);

            //Create path for ant_i
            for(int city_i = 1; city_i < Colony[ant_i].size(); ++city_i)
            {
                cout << "Calculating city number: " << city_i << endl;
                //Create roulette for next city selection
                vector<double> Roulette(RemainingCities.size(), 0);
                double total = 0;

                //DEBUGGING SECTION
                cout << "Size Roulette: " << Roulette.size() << endl;
                cout << "Size Remain: " << RemainingCities.size() << endl;
                cout << "Size Map: " << Map.size() << " x " << Map[0].size() << endl;

                int k = 0;
                cout << "Test: Map access: " << endl;
                for(int i = 0; i < Map.size(); ++i) //  HERE IT CRASHES AT ANT NUMBER 55
                    cout << Map[0][i] << " ";
                cout << endl;

                cout << "Test: Operation: " << Map[Colony[ant_i][city_i-1]][RemainingCities[k]] << endl;

                Roulette[k] = pow((MAX_DIST - Map[Colony[ant_i][city_i-1]][RemainingCities[k]]), heur_coef) + pow((pheromones[Colony[ant_i][city_i-1]][RemainingCities[k]]), pher_coef);

                //END OF DEBUGGING SECTION

                for(int j = 0; j < RemainingCities.size(); ++j)
                {
                    //Heuristic value is MAX_DIST - current edge.
                    Roulette[j] = pow((MAX_DIST - Map[Colony[ant_i][city_i-1]][RemainingCities[j]]), heur_coef) + pow((pheromones[Colony[ant_i][city_i-1]][RemainingCities[j]]), pher_coef);
                    total += Roulette[j];
                }
                cout << endl;
                //Transform roulette into stacked probabilities
                Roulette[0] = Roulette[0]/total;

                for(int j = 1; j < Roulette.size(); ++j)
                    Roulette[j] = Roulette[j-1] + Roulette[j] / total;

                //Select a city from Roulette
                int chosen = 0;
                double r = (double) rand()/RAND_MAX;
                while(Roulette[chosen] < r)
                    chosen++;

                //Add chosen city to
                Colony[ant_i][city_i] = RemainingCities[chosen];
                RemainingCities.erase(RemainingCities.begin() + chosen);
            }
            cout << endl;
            //Save cost of ant_i, for elitist expansion
            costs[ant_i] = pathCost(Colony[ant_i], Map);
        }
        i++;
    }

}

1 Ответ

1 голос
/ 02 июня 2019

Эта часть очень подозрительна:

for(int i = 0; i < Map.size(); ++i) //  HERE IT CRASHES AT ANT NUMBER 55
   cout << Map[0][i] << " ";

, потому что i - это размер карты , но вы используете его как индекс в вероятной строке /вектор, так что вы, вероятно, выходите из строки / вектора с неопределенным поведением

вероятно, вы хотите

for(int i = 0; i < Map.size(); ++i)
   cout << Map[i] << " ";

или

for(int i = 0; i < Map[0].size(); ++i)
   cout << Map[0][i] << " ";

Как я уже сказалв примечании в данный момент RemainingCities[0] значения -163172699 сначала в

 cout << "Test: Operation: " << Map.at(Colony.at(ant_i).at(city_i-1)).at(RemainingCities.at(k)) << endl;

, поэтому недопустимый индекс в Map , но есть видимая причинаПосмотрите на код, поэтому причина - вероятная запись вектора , разрушающего элементы вашей памяти.

Чтобы определить, где я заменил все [...] на .at(...), и первая ошибка, с которой я столкнулся, заключается в ACO в строке

 costs.at(ant_i) = pathCost(Colony.at(ant_i), Map);

, где ant_i имеет значение 52, а стоит , имеет 52 записи и Colony 260, поэтому ошибка касается стоит

обратите внимание, что ant_i устанавливается циклом

 for(int ant_i = 0; ant_i < num_ants; ++ant_i)

, и в этом случае num_ants значение 260 намного больше, чем размер стоит , который определяется как

 vector<double> costs(cities.size(), 0);

, но стоимость просто выделена и установлена, но никогда не читается, поэтому ее цель - просто уничтожить память.

Если я удаляюдве строки, касающиеся этого, у меня больше нет ошибки, и программа завершается нормально, исключений в .at(...) и valgrind тоже не обнаружено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...