diff --git a/Genetic-Algorithm.vcxproj b/Genetic-Algorithm.vcxproj index aa45fa0..3733113 100644 --- a/Genetic-Algorithm.vcxproj +++ b/Genetic-Algorithm.vcxproj @@ -119,11 +119,19 @@ + + + + + + + + diff --git a/Genetic-Algorithm.vcxproj.filters b/Genetic-Algorithm.vcxproj.filters index bc1d5b1..2c07236 100644 --- a/Genetic-Algorithm.vcxproj.filters +++ b/Genetic-Algorithm.vcxproj.filters @@ -18,8 +18,28 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/include/CubicEquation.h b/include/CubicEquation.h new file mode 100644 index 0000000..da6f36b --- /dev/null +++ b/include/CubicEquation.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +class CubicEquation { +public: + CubicEquation(const std::array& coefficients); + std::array solve(); + std::array getRoots() const; + std::array getCoefficients() const; + +private: + std::array coefficients_; + std::array roots_; +}; diff --git a/include/Entity.h b/include/Entity.h new file mode 100644 index 0000000..765eeb6 --- /dev/null +++ b/include/Entity.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +class Entity { +public: + // + Entity(); + Entity(const std::array& coefficients); + + // + std::array getCoefficients() const; + std::array getRoots() const; + + // + void mutate(); + Entity crossover(const Entity& other) const; + void printEquation(); + void printEntity(); + +private: + std::array coefficients; + std::array roots; + void printFormattedNumber(int num); +}; + diff --git a/include/Population.h b/include/Population.h new file mode 100644 index 0000000..6bb9a54 --- /dev/null +++ b/include/Population.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Entity.h" +#include + +class Population { +public: + // + Population(); + Population(std::array newPopulation); + + const std::array& getPopulation() const; + + void printPopulation(); + std::array calculateFitness(std::array targetRoots); + std::array Population::selection(); + std::array Population::evolve(); // + +private: + int generationNumber; + std::array sellist; + std::array fitness; + std::array population_; +}; diff --git a/main.cpp b/main.cpp index 118a02b..257ed3d 100644 --- a/main.cpp +++ b/main.cpp @@ -1,175 +1,10 @@ #include #include -#include -#include -#include - -// Вывод числа в формате с отступами -void printFormattedNumber(int num) { - if (num == 100) - std::cout << num << " "; - else if (num < 10) - std::cout << " " << num << " "; - else if (num >= 10 && num < 100) - std::cout << " " << num << " "; -} - -// Вывод текущей популяции -void printPopulation(int Generation_Number, std::array, 10> new_popul) { - - std::cout << "\nGeneration " << Generation_Number << std::endl; - std::cout << " Chromosome " << " a b c d " << "\n\n"; - - for (int i = 0; i < 10; i++) { - std::cout << "Individual " << i << " "; - - for (int j = 0; j < 4; j++) { - printFormattedNumber(new_popul[i][j]); - } - - std::cout << std::endl; - } -} - -// Генерация начальной популяции с случайными коэффициентами -std::array, 10> initial_population() { - std::array, 10> new_popul; - - for (int i = 0; i < 10; i++) { - for (int j = 0; j < 4; j++) { - new_popul[i][j] = rand() % 101; - } - } - - return new_popul; -} - -// Решение кубического уравнения -std::array solveCubicEquation(const std::array& coefficients) { - double a = coefficients[0]; - double b = coefficients[1]; - double c = coefficients[2]; - double d = coefficients[3]; - - // Calculate discriminants and intermediate values - double discriminant = 18 * a * b * c * d - 4 * b * b * b * d + b * b * c * c - 4 * a * c * c * c - 27 * a * a * d * d; - double delta0 = b * b - 3 * a * c; - double delta1 = 2 * b * b * b - 9 * a * b * c + 27 * a * a * d; - - // Calculate roots - std::array roots; - - if (discriminant > 0) { - double C = cbrt((delta1 + sqrt(discriminant)) / 2.0); - double D = cbrt((delta1 - sqrt(discriminant)) / 2.0); - roots[0] = (-b + C + D) / (3 * a); - } - else if (discriminant == 0) { - roots[0] = -b / (3 * a); - } - else { - double phi = acos(delta1 / (2 * sqrt(-delta0 * delta0 * delta0))); - double magnitude = 2 * sqrt(-delta0); - const double pi = 3.14159265358979323846; // Число π - roots[0] = magnitude * cos(phi / 3) - b / (3 * a); - roots[1] = magnitude * cos((phi + 2 * pi) / 3) - b / (3 * a); - roots[2] = magnitude * cos((phi + 4 * pi) / 3) - b / (3 * a); - } - - return roots; -} - -// Оценка приспособленности особей (близость к корням) -std::array fitness_evaluation(const std::array, 10>& population, - const std::array& target_roots) { - std::array fitness; - - for (int i = 0; i < 10; i++) { - double total_distance = 0.0; - - for (int j = 0; j < 3; j++) { - std::array roots = solveCubicEquation(population[i]); - for (int k = 0; k < 3; k++) { - double distance = std::abs(roots[k] - target_roots[j]); - total_distance += distance; - } - } - - fitness[i] = 1.0 / total_distance; - } - - return fitness; -} - -// Выбор особей для следующего поколения -std::array selection(const std::array& fitness) { - std::array sellist; - - for (int i = 0; i < 5; i++) { - int maxIndex = 0; - double maxFitness = -1.0; - - for (int j = 0; j < 10; j++) { - if (fitness[j] > maxFitness) { - bool isAlreadySelected = false; - for (int k = 0; k < i; k++) { - if (sellist[k] == j) { - isAlreadySelected = true; - break; - } - } - - if (!isAlreadySelected) { - maxIndex = j; - maxFitness = fitness[j]; - } - } - } - - sellist[i] = maxIndex; - } - - return sellist; -} - -// Создание новой популяции на основе выбранных особей -std::array, 10> createNewPopulation(const std::array, 10>& old_popul, const std::array& sellist) { - std::array, 10> new_popul; - - // Копирование выбранных особей в новую популяцию - for (int i = 0; i < 5; i++) { - new_popul[i] = old_popul[sellist[i]]; - } - - // Генерация новых особей (потомков) через скрещивание - for (int i = 5; i < 10; i++) { - int parent1Index = rand() % 5; // Выбор случайного родителя из выбранных особей - int parent2Index = rand() % 5; // Выбор еще одного случайного родителя из выбранных особей - - // Производим скрещивание (можно использовать простое скрещивание с одной точкой) - int crossoverPoint = rand() % 4; // Выбор случайной точки скрещивания - - for (int j = 0; j < 4; j++) { - if (j < crossoverPoint) { - new_popul[i][j] = old_popul[sellist[parent1Index]][j]; - } - else { - new_popul[i][j] = old_popul[sellist[parent2Index]][j]; - } - } - - // Производим мутацию - int mutationGeneIndex = rand() % 4; // Выбор случайного гена для мутации - new_popul[i][mutationGeneIndex] = rand() % 101; // Мутируем ген случайным значением - } - - return new_popul; -} - +#include "include/CubicEquation.h" +#include "include/Entity.h" +#include "include/Population.h" int main() { - srand(time(NULL)); - const int MAX_GENERATIONS = 100; // Максимальное количество поколений std::cout << "New Genetic Algorithm for Cubic Equation\n\n"; @@ -182,46 +17,44 @@ int main() { std::cin >> coefficients[i]; } - std::array roots = solveCubicEquation(coefficients); // Корни кубического уравнения - - - std::cout << std::endl << "Cubic Equation: " << coefficients[0] << "x^3 + " - << coefficients[1] << "x^2 + " << coefficients[2] << "x + " << coefficients[3] << " = 0" << std::endl; + Entity targetEquation(coefficients); + targetEquation.printEquation(); - std::cout << "Equation Roots: " << roots[0] << ", " << roots[1] << ", " << roots[2] << std::endl; + std::array roots = targetEquation.getRoots(); + + Population newPopul; + newPopul.printPopulation(); int Generation_Number = 1; - std::array sellist; // Массив наиболее приспособленных. + std::array new_popul = newPopul.getPopulation(); - std::array, 10> new_popul = initial_population(); - printPopulation(Generation_Number, new_popul); + std::array sellist; // Массив наиболее приспособленных. // Основной цикл генетического алгоритма while (true) { // Оценка приспособленности - std::array fitness_values = fitness_evaluation(new_popul, roots); + newPopul.calculateFitness(roots); // Выбор особей для следующего поколения - sellist = selection(fitness_values); - - /*По логике будет 5 прислпособленнейших и генерироваться 5 новых. - Также мутация будет менят некоторыхе хромосомы в некоторых особях, которое будет выбираться рандомом.*/ + sellist = newPopul.selection(); // Создание новой популяции на основе выбранных особей - new_popul = createNewPopulation(new_popul, sellist); + new_popul = newPopul.evolve(); Generation_Number++; // После определенного количества поколений, выводим наилучшее уравнение if (Generation_Number == MAX_GENERATIONS) { int bestIndividualIndex = sellist[0]; // Индекс самой приспособленной особи - std::array bestCoefficients = new_popul[bestIndividualIndex]; // Коэффициенты этой особи + std::array bestCoefficients = new_popul[bestIndividualIndex].getCoefficients(); // Коэффициенты этой особи std::cout << "\nBest Equation after " << MAX_GENERATIONS << " Generations:\n"; std::cout << "Cubic Equation: " << bestCoefficients[0] << "x^3 + " << bestCoefficients[1] << "x^2 + " << bestCoefficients[2] << "x + " << bestCoefficients[3] << " = 0" << std::endl; - std::array bestRoots = solveCubicEquation(bestCoefficients); // Корни уравнения + CubicEquation bestEntity(bestCoefficients); + ; + std::array bestRoots = bestEntity.solve(); // Корни уравнения std::cout << "Equation Roots: " << bestRoots[0] << ", " << bestRoots[1] << ", " << bestRoots[2] << std::endl; break; // Завершаем цикл после вывода результата diff --git a/scr/CubicEquation.cpp b/scr/CubicEquation.cpp new file mode 100644 index 0000000..47ab2c4 --- /dev/null +++ b/scr/CubicEquation.cpp @@ -0,0 +1,45 @@ +#include "../include/CubicEquation.h" +#include + +CubicEquation::CubicEquation(const std::array& coefficients) + : coefficients_(coefficients), roots_{ 0.0, 0.0, 0.0 } {} + +std::array CubicEquation::solve() { + double a = coefficients_[0]; + double b = coefficients_[1]; + double c = coefficients_[2]; + double d = coefficients_[3]; + + // Calculate discriminants and intermediate values + double discriminant = 18 * a * b * c * d - 4 * b * b * b * d + b * b * c * c - 4 * a * c * c * c - 27 * a * a * d * d; + double delta0 = b * b - 3 * a * c; + double delta1 = 2 * b * b * b - 9 * a * b * c + 27 * a * a * d; + + // Calculate roots + if (discriminant > 0) { + double C = cbrt((delta1 + sqrt(discriminant)) / 2.0); + double D = cbrt((delta1 - sqrt(discriminant)) / 2.0); + roots_[0] = (-b + C + D) / (3 * a); + } + else if (discriminant == 0) { + roots_[0] = -b / (3 * a); + } + else { + double phi = acos(delta1 / (2 * sqrt(-delta0 * delta0 * delta0))); + double magnitude = 2 * sqrt(-delta0); + const double pi = 3.14159265358979323846; + roots_[0] = magnitude * cos(phi / 3) - b / (3 * a); + roots_[1] = magnitude * cos((phi + 2 * pi) / 3) - b / (3 * a); + roots_[2] = magnitude * cos((phi + 4 * pi) / 3) - b / (3 * a); + } + + return roots_; +} + +std::array CubicEquation::getRoots() const { + return roots_; +} + +std::array CubicEquation::getCoefficients() const{ + return coefficients_; +} \ No newline at end of file diff --git a/scr/Entity.cpp b/scr/Entity.cpp new file mode 100644 index 0000000..2e3594b --- /dev/null +++ b/scr/Entity.cpp @@ -0,0 +1,75 @@ +#include "../include/Entity.h" +#include "../include/CubicEquation.h" +#include +#include +#include + +Entity::Entity() { + srand(time(NULL)); + + for (int i = 0; i < 4; i++) { + coefficients[i] = rand() % 101; + } + + CubicEquation equation(coefficients); + roots = equation.solve(); +} + +Entity::Entity(const std::array& coefficients) { + this->coefficients = coefficients; + + CubicEquation equation(coefficients); + roots = equation.solve(); +} + +std::array Entity::getCoefficients() const { + return coefficients; +} + +std::array Entity::getRoots() const { + return roots; +} + +void Entity::mutate() { + int geneIndex = rand() % 4; + coefficients[geneIndex] = rand() % 101; +} + +Entity Entity::crossover(const Entity& other) const { + int crossoverPoint = rand() % 4; + std::array newCoefficients; + + for (int i = 0; i < 4; i++) { + if (i < crossoverPoint) { + newCoefficients[i] = coefficients[i]; + } + else { + newCoefficients[i] = other.coefficients[i]; + } + } + + return Entity(newCoefficients); +} + +void Entity::printEquation() { + std::cout << std::endl << "Equation: " << coefficients[0] << "x^3 + " + << coefficients[1] << "x^2 + " << coefficients[2] << "x + " << coefficients[3] << " = 0" << std::endl; + + std::cout << "Equation Roots: " << roots[0] << ", " << roots[1] << ", " << roots[2] << std::endl; +} + +void Entity::printEntity() { + for (int i = 0; i < 4; i++) { + printFormattedNumber(coefficients[i]); + } +} + +// +void Entity::printFormattedNumber(int num) { + if (num == 100) + std::cout << num << " "; + else if (num < 10) + std::cout << " " << num << " "; + else if (num >= 10 && num < 100) + std::cout << " " << num << " "; +} \ No newline at end of file diff --git a/scr/Population.cpp b/scr/Population.cpp new file mode 100644 index 0000000..6fe745d --- /dev/null +++ b/scr/Population.cpp @@ -0,0 +1,110 @@ +#include "../include/Population.h" +#include "../include/Entity.h" +#include +#include +#include +#include + +// +Population::Population() { + generationNumber = 1; + + for (int i = 0; i < 10; i++) { + + population_[i] = Entity::Entity(); + } +} + +Population::Population(std::array newPopulation) { + generationNumber = 1; + population_ = newPopulation; +} + +const std::array& Population::getPopulation() const { + return population_; +} + +// +std::array Population::evolve() { + std::array new_popul; + + // + for (int i = 0; i < 5; i++) { + new_popul[i] = population_[sellist[i]]; + } + + // () + for (int i = 5; i < 10; i++) { + new_popul[i] = Entity::Entity(); + } + + for (int i = 0; i < 10; i++) { + population_[i] = new_popul[i]; + } + + return population_; +} + +// ( ) +std::array Population::calculateFitness(std::array target_roots) { + for (int i = 0; i < 10; i++) { + double total_distance = 0.0; + + for (int j = 0; j < 3; j++) { + std::array roots = population_[i].getRoots(); + + for (int k = 0; k < 3; k++) { + double distance = std::abs(roots[k] - target_roots[j]); + total_distance += distance; + } + } + + fitness[i] = 1.0 / total_distance; + } + + return fitness; +} + +// +std::array Population::selection() { + std::array sellist; + + for (int i = 0; i < 5; i++) { + int maxIndex = 0; + double maxFitness = -1.0; + + for (int j = 0; j < 10; j++) { + if (fitness[j] > maxFitness) { + bool isAlreadySelected = false; + for (int k = 0; k < i; k++) { + if (sellist[k] == j) { + isAlreadySelected = true; + break; + } + } + + if (!isAlreadySelected) { + maxIndex = j; + maxFitness = fitness[j]; + } + } + } + + sellist[i] = maxIndex; + } + + return sellist; +} + +// +void Population::printPopulation() { + + std::cout << "\nGeneration " << generationNumber << std::endl; + std::cout << " Chromosome " << " a b c d " << "\n\n"; + + for (int i = 0; i < 10; i++) { + std::cout << "Individual " << i << " "; + population_[i].printEntity(); + std::cout << std::endl; + } +} \ No newline at end of file