Две версии функции не дают одинакового результата - PullRequest
0 голосов
/ 26 октября 2019

Предположим, что у нас есть stack, заполненный 0 и 1. Я хочу изменить mutation_rate_ многих элементов с 0 на 1 и наоборот. Элементы, которые должны быть «видоизменены», выбираются случайным образом. Я написал две функции для этого, которые я опубликую ниже вместе с тестовым примером, но одна из них, похоже, не работает должным образом.

#include <stack>
#include <vector>
#include <random>
#include <set>
#include <algorithm>
#include <iostream>

using age_t = unsigned int;

std::stack<age_t>  mutate( std::stack<age_t>  genome_, age_t mutation_rate_ = 3){
    std::stack<age_t> final_stack;

    // Generate a set, whose elements are the positions at which we perforem the mutation.
    std::set<age_t> positions_to_switch;
    while(positions_to_switch.size() < mutation_rate_){
        positions_to_switch.insert(rand() % genome_.size());
    }

    // Create a counter to go through the stack amd iterator of the set.
    age_t cnt = 0;
    std::set<age_t>::iterator it= positions_to_switch.begin();

    while(genome_.empty()!=true){                               // Go through the whole genome_
        if(*it==cnt){                                           // check if current position in stack matches with
                                                                // element that needs mutation
            if(genome_.top()==1) final_stack.push(0);           // mutate
            else final_stack.push(1);
            ++it;                                               // go to next element that needs mutation
        }
        else{                                                   // if no mutation is needed
            final_stack.push(genome_.top());
        }
        genome_.pop();                                          // go to next element in stack
        ++cnt;                                                  // increase counter of stack
    }

    // final stack is in reverse order
    std::stack<age_t> res;
    while(!final_stack.empty()){
        res.push(final_stack.top());
        final_stack.pop();
    }
    return res;
};

std::stack<age_t> mutate_2( std::stack<age_t>  genome_, age_t mutation_rate_ = 3){
    std::stack<age_t> final_stack;

    std::vector<age_t> enumeration;
    age_t pos = 0;
    while(enumeration.size() < genome_.size()){
        enumeration.push_back(pos);
        ++pos;
    }
    pos = 0;

    auto rng = std::default_random_engine {};
    std::shuffle(enumeration.begin(), enumeration.end(), rng);

    std::vector<age_t> positions_to_switch;
    while(positions_to_switch.size() < mutation_rate_){
        positions_to_switch.push_back(enumeration[pos]);
        ++pos;
    }

    // Create a counter to go through the stack amd iterator of the set.
    age_t cnt = 0;
    std::vector<age_t>::iterator it= positions_to_switch.begin();

    while(genome_.empty()!=true){                           // Go through the whole genome_
        if(*it==cnt){                                       // check if current position in stack matches with
                                                            // element that needs mutation
            if(genome_.top()==1) final_stack.push(0);       // mutate
            else final_stack.push(1);
            ++it;                                           // go to next element that needs mutation
        }
        else{                                               // if no mutation is needed
            final_stack.push(genome_.top());
        }
        genome_.pop();                                      // go to next element in stack
        ++cnt;                                              // increase counter of stack
    }

    // final stack is in reverse order
    std::stack<age_t> res;
    while(!final_stack.empty()){
        res.push(final_stack.top());
        final_stack.pop();
    }
    return res;
};

int main(){

    std::stack<age_t> test_stack;
    test_stack.push(1);
    test_stack.push(0);
    test_stack.push(0);
    test_stack.push(0);
    test_stack.push(1);
    test_stack.push(1);

    std::stack<age_t> test_stack_copy = test_stack;
    std::stack<age_t> test_stack_copy_2 = test_stack;

    std::stack<age_t> res = mutate(test_stack);
    std::stack<age_t> res_2 = mutate_2(test_stack);


    std::cout << "Original Stack:\t";
    while(test_stack_copy_2.empty()!=true){
        std::cout << test_stack_copy_2.top();
        test_stack_copy_2.pop();
    }
    std::cout << "\n";

    std::cout << "Muatet:\t\t";
    while(res.empty()!=true){
        std::cout << res.top();
        res.pop();
    }
    std::cout << "\n";

    std::cout << "Muatet_2:\t";
    while(res_2.empty()!=true){
        std::cout << res_2.top();
        res_2.pop();
    }
    std::cout << "\n";

    return 0;
}

Учитывая тестовый пример 110001, mutate возвращает 100111 и mutate_2 возвращает 111101, где я установил mutation_rate_=3, поэтому три элемента исходного стека должны были быть изменены. Мы можем непосредственно видеть, что mutate действительно изменил три записи, в то время как mutate_2 изменил только две из них ... Я уверен, что это как-то связано с обработкой объектов set и vector,но я просто не могу найти ошибку ...

Ответы [ 2 ]

2 голосов
/ 26 октября 2019

В первом случае вы используете std :: set, который содержит отсортированные элементы (позиции) в порядке возрастания.

Во втором случае вектор с позициями не сортируется.

Включите сортировку вектора

std::sort( positions_to_switch.begin(), positions_to_switch.end() );
1 голос
/ 26 октября 2019

Содержимое std::set автоматически сортируется, а std::vector - нет.

Когда результат перемешивания не в порядке возрастания (например, {2, 1, 3}), Маленькийэлементы (1 в примере) игнорируются, так как значение пропускается при проверке большего элемента (в примере 2).

добавление сортировки

    std::sort(positions_to_switch.begin(), positions_to_switch.end());

после элементадобавление части

    std::vector<age_t> positions_to_switch;
    while(positions_to_switch.size() < mutation_rate_){
        positions_to_switch.push_back(enumeration[pos]);
        ++pos;
    }

решит эту проблему.

Другая проблема заключается в том, что итератор it может находиться после последнего элемента при чтении на жгуте *it==cnt.
Проверкадолжен быть вставлен как it!=positions_to_switch.end() && *it==cnt.
(В этом коде it не будет считываться, когда it==positions_to_switch.end() благодаря оценке короткого замыкания.)

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