Newer
Older

Michal Kravcenko
committed
/**
* DESCRIPTION OF THE FILE
*
* @author Michal Kravčenko
* @date 2.7.18 -
*/
Martin Beseda
committed
#include <cmath>
#include <set>
#include <stdexcept>

Michal Kravcenko
committed
#include "ParticleSwarm.h"
/**
* TODO
* domain_bound out_of_range check
* @param f_dim
* @param domain_bounds
* @param F
*/

Michal Kravcenko
committed
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
Particle::Particle(unsigned int f_dim, double *domain_bounds, double (*F)(double*)) {
this->coordinate_dim = f_dim;
this->coordinate = new double[f_dim];
this->velocity = new double[f_dim];
for(unsigned int i = 0; i < f_dim; ++i){
this->velocity[i] = (rand() % 100001 - 50000) / (double) 50000;
}
// this->r1 = (rand() % 100001) / (double) 100000;
// this->r2 = (rand() % 100001) / (double) 100000;
this->r1 = 1.0;
this->r2 = 1.0;
this->optimal_coordinate = new double[f_dim];
this->f = F;
this->domain_bounds = domain_bounds;
for(unsigned int i = 0; i < f_dim; ++i){
this->coordinate[i] = (rand() % 100001) / (double)100000 * (domain_bounds[2 * i + 1] - domain_bounds[2 * i]) + domain_bounds[2 * i];
this->optimal_coordinate[i] = this->coordinate[i];
}
this->optimal_value = this->f(this->coordinate);
// this->print_coordinate();
}
Particle::~Particle() {
if( this->optimal_coordinate ){
delete [] this->optimal_coordinate;
}
if( this->coordinate ){
delete [] this->coordinate;
}
if( this->velocity ){
delete [] this->velocity;
}
}
Martin Beseda
committed
double* Particle::get_coordinate() {
return this->coordinate;
}

Michal Kravcenko
committed
double Particle::get_optimal_value() {
return this->optimal_value;
}
void Particle::get_optimal_coordinate(double *ref_coordinate) {
for( unsigned int i = 0; i < this->coordinate_dim; ++i ){
ref_coordinate[i] = this->optimal_coordinate[i];
}
}
Martin Beseda
committed
double Particle::change_coordinate(double w, double c1, double c2, double *glob_min_coord, double penalty_coef) {

Michal Kravcenko
committed
/**
* v = w * v + c1r1(p_min_loc - x) + c2r2(p_min_glob - x)
* x = x + v
*/
Martin Beseda
committed
double vel_mem;
double output;
bool in_domain;
double compensation_coef = 1;

Michal Kravcenko
committed
for(unsigned int i = 0; i < this->coordinate_dim; ++i){
vel_mem = w * this->velocity[i] + c1 * this->r1 * (this->optimal_coordinate[i] - this->coordinate[i]) + c2 * this->r2 * (glob_min_coord[i] - this->coordinate[i]);
Martin Beseda
committed
do{
if (this->coordinate[i] + vel_mem > this->domain_bounds[2 * i + 1]) {
in_domain = false;
vel_mem = -penalty_coef * compensation_coef * w * vel_mem;
compensation_coef /= 2;
} else if (this->coordinate[i] + vel_mem < this->domain_bounds[2 * i]) {
in_domain = false;
vel_mem = penalty_coef * compensation_coef * w * vel_mem;
compensation_coef /= 2;
} else {
in_domain = true;
compensation_coef = 1;
}
}while(!in_domain);

Michal Kravcenko
committed
this->velocity[i] = vel_mem;
this->coordinate[i] += vel_mem;
Martin Beseda
committed
output += std::abs(vel_mem);

Michal Kravcenko
committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
}
vel_mem = this->f(this->coordinate);
if(vel_mem < this->optimal_value){
this->optimal_value = vel_mem;
for(unsigned int i = 0; i < this->coordinate_dim; ++i){
this->optimal_coordinate[i] = this->coordinate[i];
}
}
return output;
}
void Particle::print_coordinate() {
for(unsigned int i = 0; i < this->coordinate_dim - 1; ++i){
printf("%10.8f, ", this->coordinate[i]);
}
printf("%10.8f\n", this->coordinate[this->coordinate_dim - 1]);
}
ParticleSwarm::ParticleSwarm(double (*F)(double*), unsigned int f_dim, double *domain_bounds, double c1, double c2, double w,
unsigned int n_particles, unsigned int iter_max) {
srand(time(NULL));
this->func = F;
this->func_dim = f_dim;
this->c1 = c1;
this->c2 = c2;
this->w = w;
this->n_particles = n_particles;
this->iter_max = iter_max;
this->particle_swarm = new Particle*[this->n_particles];
for( unsigned int pi = 0; pi < this->n_particles; ++pi ){
this->particle_swarm[pi] = new Particle( f_dim, domain_bounds, F);
}
this->domain_bounds = domain_bounds;
}
ParticleSwarm::~ParticleSwarm() {
if( this->particle_swarm ){
for( unsigned int i = 0; i < this->n_particles; ++i ){
delete this->particle_swarm[i];
}
delete [] this->particle_swarm;
}
}
Martin Beseda
committed
/**
*
* @param gamma
* @param epsilon
* @param delta
*/
void ParticleSwarm::optimize( double gamma, double epsilon, double delta) {
if(epsilon < 0 || gamma < 0 || delta < 0) {
throw std::invalid_argument("Parameters 'gamma', 'epsilon' and 'delta' must be greater than or equal to zero!");
}

Michal Kravcenko
committed
unsigned int outer_it = 0;
Particle *particle;
double *p_min_glob = new double[this->func_dim];
double optimal_value;
Martin Beseda
committed
std::set<Particle*> cluster; //!< Particles in a cluster
double* coords;
coords = new double[this->func_dim]; //<! Centroid coordinates

Michal Kravcenko
committed
Martin Beseda
committed
double tmp_velocity;
double prev_max_velocity = 0;
double max_velocity;
double max_vel_step = 0;
double prev_max_vel_step;

Michal Kravcenko
committed
Martin Beseda
committed
while( outer_it < this->iter_max ) {
max_velocity = 0;

Michal Kravcenko
committed
Martin Beseda
committed
//////////////////////////////////////////////////
// Clustering algorithm - termination condition //
//////////////////////////////////////////////////
particle = this->determine_optimal_coordinate_and_value(p_min_glob, optimal_value);
cluster.insert(particle);

Michal Kravcenko
committed
Martin Beseda
committed
for(unsigned int i=0; i < 5; i++) {

Michal Kravcenko
committed
Martin Beseda
committed
/* Looking for a centroid */
for (auto it : cluster) {
for (unsigned int di = 0; di < this->func_dim; di++) {
coords[di] += it->get_coordinate()[di];
}

Michal Kravcenko
committed
}
Martin Beseda
committed
for(unsigned int di = 0; di < this->func_dim; di++) {
coords[di] /= cluster.size();
}
for(unsigned int pi=0; pi < this->n_particles; pi++) {
particle = this->particle_swarm[pi];
tmp_velocity = particle->change_coordinate( this->w, this->c1, this->c2, p_min_glob);
if(tmp_velocity > max_velocity) {
prev_max_velocity = max_velocity;
max_velocity = tmp_velocity;
}
/* Looking for nearby particles */
printf("iter: %d, pi: %d, euclidean dist: %f\n", outer_it, pi, this->get_euclidean_distance(particle->get_coordinate(), coords, this->func_dim));
if(this->get_euclidean_distance(particle->get_coordinate(), coords, this->func_dim) < epsilon) {
cluster.insert(particle);
}
}
}

Michal Kravcenko
committed
Martin Beseda
committed
prev_max_vel_step = max_vel_step;
max_vel_step = max_velocity - prev_max_velocity;

Michal Kravcenko
committed
Martin Beseda
committed
/* Check if the particles are near to each other AND the maximal velocity is less than 'gamma' */
// printf("cluster size: %ld, n particles: %d, %f\n", cluster.size(), this->n_particles, double(cluster.size())/this->n_particles);
printf("cluster: %f\n", double(cluster.size())/this->n_particles);
printf("real gamma: %f\n", std::abs(prev_max_vel_step/max_vel_step));
if(double(cluster.size())/this->n_particles > delta && std::abs(prev_max_vel_step/max_vel_step) > gamma) {
break;
}

Michal Kravcenko
committed
outer_it++;
Martin Beseda
committed
// this->w *= 0.99;

Michal Kravcenko
committed
}
printf("Found optimum in %6d iterations: %10.8f at coordinate: ", outer_it, optimal_value);
for(unsigned int i = 0; i < this->func_dim - 1; ++i){
printf("%10.8f, ", p_min_glob[i]);
}
printf("%10.8f\n", p_min_glob[this->func_dim - 1]);
delete [] p_min_glob;
Martin Beseda
committed
delete [] coords;

Michal Kravcenko
committed
}
Martin Beseda
committed
Particle* ParticleSwarm::determine_optimal_coordinate_and_value(double *coord, double &val) {
Particle* p;

Michal Kravcenko
committed
val = this->particle_swarm[0]->get_optimal_value( );
this->particle_swarm[0]->get_optimal_coordinate(coord);
Martin Beseda
committed
p = this->particle_swarm[0];

Michal Kravcenko
committed
for(unsigned int i = 1; i < this->n_particles; ++i){
double val_m = this->particle_swarm[i]->get_optimal_value( );
if(val_m < val){
val = val_m;
this->particle_swarm[i]->get_optimal_coordinate(coord);
Martin Beseda
committed
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
p = this->particle_swarm[i];
}
}
return p;
}
double* ParticleSwarm::get_centroid_coordinates() {
double* coords = new double[this->func_dim];
double* tmp;
for (unsigned int pi = 0; pi < this->n_particles; pi++) {
tmp = this->particle_swarm[pi]->get_coordinate();
for (unsigned int di = 0; di < this->func_dim; di++) {
coords[di] += tmp[di];
}
}
for(unsigned int di = 0; di < this->func_dim; di++) {
coords[di] /= this->n_particles;
}
return coords;
}
double ParticleSwarm::get_euclidean_distance(double* a, double* b, unsigned int n) {
Martin Beseda
committed
double dist = 0;
for(unsigned int i = 0; i < n; i++) {
if((a[i]-b[i]) * (a[i]-b[i]) > 1000) {

Michal Kravcenko
committed
}
Martin Beseda
committed
dist += ((a[i]-b[i]) * (a[i]-b[i]));

Michal Kravcenko
committed
}
Martin Beseda
committed
return std::sqrt(dist);