Minimum Finder  1.0
Find the minimum of one multi-dimss function
Loading...
Searching...
No Matches
methods.cpp
Go to the documentation of this file.
1/*
2@Author: Gilbert Young
3@Time: 2024/09/19 08:56
4@File_name: methods.cpp
5@Description:
6Implementation file containing definitions of the optimization methods:
71. Steepest Descent Method
82. Conjugate Gradient Method
93. Simulated Annealing
104. Genetic Algorithm
11*/
12
13#include "methods.h"
14#include "functions.h"
15#include <cmath>
16#include <chrono>
17#include <cstdlib>
18#include <ctime>
19#include <vector>
20
21// Steepest Descent Method
22Result steepestDescent(double x0, double y0, double alpha, int maxIter, double tol)
23{
24 Result res;
25 auto start = std::chrono::high_resolution_clock::now();
26 double x = x0, y = y0, dx, dy;
27 res.iterations = 0;
28
29 for (int i = 0; i < maxIter; ++i)
30 {
31 computeGradient(x, y, dx, dy);
32 double norm = sqrt(dx * dx + dy * dy);
33 if (norm < tol)
34 {
35 res.iterations = i;
36 break;
37 }
38 // Update positions
39 x -= alpha * dx;
40 y -= alpha * dy;
41 res.iterations = i + 1;
42 }
43
44 auto end = std::chrono::high_resolution_clock::now();
45 res.duration = std::chrono::duration<double>(end - start).count();
46 res.x = x;
47 res.y = y;
48 res.f = functionToMinimize(x, y);
49 return res;
50}
51
52// Nonlinear Conjugate Gradient Method (Fletcher-Reeves)
53Result conjugateGradient(double x0, double y0, int maxIter, double tol)
54{
55 Result res;
56 auto start = std::chrono::high_resolution_clock::now();
57 double x = x0, y = y0, dx, dy;
58 computeGradient(x, y, dx, dy);
59 double g0 = dx * dx + dy * dy;
60 double d_x = -dx;
61 double d_y = -dy;
62 res.iterations = 0;
63
64 for (int i = 0; i < maxIter; ++i)
65 {
66 // Line search to find optimal alpha
67 double alpha = lineSearchBacktracking(x, y, d_x, d_y);
68 // Update positions
69 x += alpha * d_x;
70 y += alpha * d_y;
71 // Compute new gradient
72 double new_dx, new_dy;
73 computeGradient(x, y, new_dx, new_dy);
74 double gk_new = new_dx * new_dx + new_dy * new_dy;
75 // Check for convergence
76 if (sqrt(gk_new) < tol)
77 {
78 res.iterations = i + 1;
79 break;
80 }
81 // Compute beta (Fletcher-Reeves)
82 double beta = gk_new / g0;
83 // Update directions
84 d_x = -new_dx + beta * d_x;
85 d_y = -new_dy + beta * d_y;
86 // Update gradient magnitude
87 g0 = gk_new;
88 res.iterations = i + 1;
89 }
90
91 auto end = std::chrono::high_resolution_clock::now();
92 res.duration = std::chrono::duration<double>(end - start).count();
93 res.x = x;
94 res.y = y;
95 res.f = functionToMinimize(x, y);
96 return res;
97}
98
99// Simulated Annealing
100Result simulatedAnnealing(double x0, double y0, double T0, double Tmin, double alpha, int maxIter)
101{
102 Result res;
103 auto start = std::chrono::high_resolution_clock::now();
104 double x = x0, y = y0, f_current = functionToMinimize(x, y);
105 double T = T0;
106 res.iterations = 0;
107
108 for (int i = 0; i < maxIter && T > Tmin; ++i)
109 {
110 // Generate new candidate solution
111 double x_new = x + ((double)rand() / RAND_MAX - 0.5);
112 double y_new = y + ((double)rand() / RAND_MAX - 0.5);
113 double f_new = functionToMinimize(x_new, y_new);
114 double delta = f_new - f_current;
115
116 // Accept new solution if better, or with a probability
117 if (delta < 0 || exp(-delta / T) > ((double)rand() / RAND_MAX))
118 {
119 x = x_new;
120 y = y_new;
121 f_current = f_new;
122 }
123
124 // Cool down
125 T *= alpha;
126 res.iterations = i + 1;
127 }
128
129 auto end = std::chrono::high_resolution_clock::now();
130 res.duration = std::chrono::duration<double>(end - start).count();
131 res.x = x;
132 res.y = y;
133 res.f = f_current;
134 return res;
135}
136
137// Genetic Algorithm
138Result geneticAlgorithm(int populationSize, int generations, double mutationRate, double crossoverRate)
139{
140 Result res;
141 auto start = std::chrono::high_resolution_clock::now();
142 std::vector<Individual> population(populationSize);
143 double xMin = -10.0, xMax = 10.0;
144 double yMin = -10.0, yMax = 10.0;
145
146 // Initialize population
147 for (auto &ind : population)
148 {
149 ind.x = xMin + (xMax - xMin) * ((double)rand() / RAND_MAX);
150 ind.y = yMin + (yMax - yMin) * ((double)rand() / RAND_MAX);
151 ind.fitness = functionToMinimize(ind.x, ind.y);
152 }
153
154 res.iterations = generations * populationSize;
155
156 for (int gen = 0; gen < generations; ++gen)
157 {
158 // Selection (Tournament Selection)
159 std::vector<Individual> newPopulation;
160 for (int i = 0; i < populationSize; ++i)
161 {
162 int a = rand() % populationSize;
163 int b = rand() % populationSize;
164 Individual parent = population[a].fitness < population[b].fitness ? population[a] : population[b];
165 newPopulation.push_back(parent);
166 }
167
168 // Crossover (Single-point)
169 for (int i = 0; i < populationSize - 1; i += 2)
170 {
171 if (((double)rand() / RAND_MAX) < crossoverRate)
172 {
173 double alpha = (double)rand() / RAND_MAX;
174 double temp_x1 = alpha * newPopulation[i].x + (1 - alpha) * newPopulation[i + 1].x;
175 double temp_y1 = alpha * newPopulation[i].y + (1 - alpha) * newPopulation[i + 1].y;
176 double temp_x2 = alpha * newPopulation[i + 1].x + (1 - alpha) * newPopulation[i].x;
177 double temp_y2 = alpha * newPopulation[i + 1].y + (1 - alpha) * newPopulation[i].y;
178 newPopulation[i].x = temp_x1;
179 newPopulation[i].y = temp_y1;
180 newPopulation[i + 1].x = temp_x2;
181 newPopulation[i + 1].y = temp_y2;
182 }
183 }
184
185 // Mutation
186 for (auto &ind : newPopulation)
187 {
188 if (((double)rand() / RAND_MAX) < mutationRate)
189 {
190 ind.x += ((double)rand() / RAND_MAX - 0.5);
191 ind.y += ((double)rand() / RAND_MAX - 0.5);
192 // Clamp to search space
193 if (ind.x < xMin)
194 ind.x = xMin;
195 if (ind.x > xMax)
196 ind.x = xMax;
197 if (ind.y < yMin)
198 ind.y = yMin;
199 if (ind.y > yMax)
200 ind.y = yMax;
201 }
202 ind.fitness = functionToMinimize(ind.x, ind.y);
203 }
204
205 population = newPopulation;
206 }
207
208 // Find best individual
209 Individual best = population[0];
210 for (const auto &ind : population)
211 {
212 if (ind.fitness < best.fitness)
213 best = ind;
214 }
215
216 auto end = std::chrono::high_resolution_clock::now();
217 res.duration = std::chrono::duration<double>(end - start).count();
218 res.x = best.x;
219 res.y = best.y;
220 res.f = best.fitness;
221 return res;
222}
void computeGradient(double x, double y, double &dx, double &dy)
Definition functions.cpp:19
double functionToMinimize(double x, double y)
Definition functions.cpp:13
double lineSearchBacktracking(double x, double y, double d_x, double d_y, double alpha_init, double rho, double c)
Definition functions.cpp:26
Result simulatedAnnealing(double x0, double y0, double T0, double Tmin, double alpha, int maxIter)
Definition methods.cpp:100
Result steepestDescent(double x0, double y0, double alpha, int maxIter, double tol)
Definition methods.cpp:22
Result conjugateGradient(double x0, double y0, int maxIter, double tol)
Definition methods.cpp:53
Result geneticAlgorithm(int populationSize, int generations, double mutationRate, double crossoverRate)
Definition methods.cpp:138
double x
Definition structs.h:20
double fitness
Definition structs.h:22
double y
Definition structs.h:21
double duration
Definition structs.h:64
double f
Definition structs.h:62
double y
Definition structs.h:61
double x
Definition structs.h:60
int iterations
Definition structs.h:63