Я пытаюсь заниматься генетическим программированием на C++. Я собрал версию этого кода на Python, и она работала нормально (это было просто СЛИШКОМ МЕДЛЕННО). Основная предпосылка - рассматривать программы как древовидные выражения и развивать их.
Вот код для создания только одного дерева кандидатов (деревья хранятся как векторы узлов, которые указывают на своих дочерних узлов по индексу дочернего узла в том же векторе) (см. Функцию grow_tree):
Этот код компилируется нормально :) Я компилирую с помощью g ++, чтобы получить файл a.out, который я запускаю с помощью ./a.out
Моя проблема в том, что иногда он работает и завершается нормально, а иногда просто зависает и ничего не делает (тоже не выдает ошибок)
Любая помощь по этому вопросу будет принята с благодарностью! Спасибо!
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <math.h>
const int MAX_TREE_DEPTH = 5;
int randint(int min, int max) {
return (rand() % ((max - min) + 1)) + min;
}
struct node {
int type, op, req_ch;
std::vector<int> ch;
std::map<std::string, float> params;
node(int p, int rem_depth) {
if ((p == -1) || (p == 0)) {
req_ch = 2;
if (rem_depth >= 2) {
type = randint(0, 1);
if (type == 0) {
op = randint(0, 1);
} else if (type == 1) {
op = randint(2, 5);
}
} else {
type = 1;
op = randint(2, 5);
}
} else if (p == 1) {
type = 2;
if (rem_depth >= 1) {
op = randint(6, 11);
} else { op = 11; }
if ((op >= 6) && (op <= 10)) {
req_ch = 2;
} else if (op >= 11) { req_ch = 0; }
}
}
};
void grow_tree(std::vector<node>* func, int p, int rem_depth) {
node n(p, rem_depth);
func->push_back(n);
int i = func->size() - 1;
for (int j = 0; j < n.req_ch; j++) {
func->at(i).ch.push_back(func->size());
grow_tree(func, n.type, rem_depth - 1);
}
}
struct rule {
float score;
bool scored;
std::vector<node> func;
rule(int m) {
if (m == 0) { // Random initialisation
int depth = randint(2, MAX_TREE_DEPTH);
grow_tree(&func, -1, depth);
}
}
};
int main(void) {
srand(time(NULL)); // Seed the random number generator
int depth = randint(2, MAX_TREE_DEPTH);
std::vector<node> f;
grow_tree(&f, -1, depth);
return 0;
}
Бывают случаи, когда вы не присваиваете значения всем членам node.
И чтобы добавить к комментарию @molbdnilo, вы можете проверить это, распечатав значения op, p и т. д. Перед возвратом из конструктора node, чтобы точно подтвердить, какие значения используются. Если одно из этих значений является «диким», это один из способов подтвердить, что вы используете неинициализированное значение. Или вы можете инициализировать все на -1 и посмотреть, осталось ли какое-либо из этих значений -1, снова подтверждая, что вы не установили все значения в конструкторе. Все дело в отладке и обучении отладке кода.
Из любопытства, какова была производительность кода Python по сравнению с кодом C++? По моему опыту, Python обычно запускается вдвое дольше. Но могут быть смягчающие факторы, которые могут сделать его равным с C++, или C++ может быть значительно быстрее (на порядок, возможно, даже на два порядка). И это при «прочих равных» (например, тот же алгоритм; соответствующие структуры данных).





Как указывает @molbdnilo, ваш конструктор node восприимчив к наличию переменных, которые не инициализируются после возврата конструктора. Затем вы используете переменные экземпляра node здесь, в grow_tree:
for (int j = 0; j < n.req_ch; j++) {
Если n.req_ch - неинициализированное или «дикое» значение, цикл может продолжаться очень долго. Представьте, если бы n.req_ch вернулся со значением, близким к (при условии, что 32-битные целые числа), 2^32 - 1. Ваш цикл будет продолжаться более 2 000 000 000 итераций.
Чтобы подтвердить это, если вы инициализировали свой член переменных node значением, вы можете легко вывести эти переменные, чтобы увидеть, было ли изменено начальное значение. Если значение не было изменено, это подтверждает, что вы используете неинициализированные значения в своей функции grow_tree.
Пример:
node(int p, int rem_depth) :type(-100), op(-100), req_ch(-100) // Initialize everything to -100
{
// your code
...
// now check if all the variables have been initialized (values were changed from -100)
if ( type == -100 || op == -100 || req_ch == -100 )
{
std::cout << "Oops. I'm using uninitialized values for p = " << p <<
" rem_depth = " << rem_depth << "\n";
std::cout << type << " " << op << " " << req_ch << "\n\n";
}
}
Вот ваш код, измененный с помощью чека.
Как видите, ваш конструктор node не устанавливает все значения, и вы будете использовать эти значения позже в grow_tree.
Итак, ответ на вашу проблему - вернуться и закрыть дыру в конструкторе node, чтобы ваши переменные были инициализированы.