|
1 | 1 | import copy
|
| 2 | +import numpy as np |
2 | 3 | import functools
|
3 | 4 | import random
|
4 | 5 | import math
|
5 | 6 |
|
6 | 7 | from particle import Fish
|
7 | 8 | from parameters import num_of_individuos, dimensions, iterations_number
|
8 | 9 |
|
| 10 | +# np.random.seed(42) |
9 | 11 |
|
10 | 12 | class FSS():
|
11 | 13 |
|
12 |
| - def __init__(self, function_wrapper): |
13 |
| - self.function = function_wrapper |
| 14 | + def __init__(self, objective_function): |
| 15 | + self.function = objective_function |
| 16 | + self.dimensions = dimensions |
| 17 | + self.iterations_number = iterations_number |
| 18 | + self.num_of_individuos = num_of_individuos |
| 19 | + self.cluster = [] |
| 20 | + self.global_best = float('inf') |
| 21 | + self.global_best_position = [] |
| 22 | + |
| 23 | + # Params |
| 24 | + self.total_weight = 1 * self.num_of_individuos |
| 25 | + self.initial_step_ind = 0.1 |
| 26 | + self.final_step_ind = 0.0001 |
| 27 | + self.step_ind = self.initial_step_ind * (objective_function.upper_bound - objective_function.lower_bound) |
| 28 | + self.initial_step_vol = 0.01 |
| 29 | + self.final_step_vol = 0.001 |
| 30 | + self.step_vol = self.initial_step_vol * (objective_function.upper_bound - objective_function.lower_bound) |
| 31 | + self.list_global_best_values = [] |
14 | 32 |
|
15 | 33 | def search(self):
|
16 |
| - bests = [] |
17 |
| - maximum_weight_value = 1000 |
18 |
| - individual_step_dacay = 0.00005 |
19 |
| - self._initialize_particles() |
20 |
| - |
21 |
| - for iterations in range(iterations_number): |
22 |
| - |
23 |
| - # individual_movement |
24 |
| - fitness_variations = [] |
25 |
| - for fish in self.population: |
26 |
| - new_position = fish.individual_movement() |
27 |
| - new_fish = Fish(fish.function_wrapper, new_position, fish.weights) |
28 |
| - new_fish.aply_function_on_current_position() |
29 |
| - fish.aply_function_on_current_position() |
30 |
| - |
31 |
| - if new_fish.fitness < fish.fitness: |
32 |
| - new_fish.previous_position = fish.current_position |
33 |
| - fish = new_fish |
34 |
| - else: |
35 |
| - fish.previous_position = fish.current_position |
36 |
| - |
37 |
| - fitness_variations.append(abs(new_fish.fitness - fish.fitness)) |
38 |
| - |
39 |
| - # feed fishes |
40 |
| - max_variation = max(fitness_variations) |
41 |
| - for fish in self.population: |
42 |
| - new_weight = fish.weights + (fish.fitness / max_variation) |
43 |
| - fish.previous_weight = fish.weights |
44 |
| - fish.weights = new_weight |
45 |
| - if fish.weights > maximum_weight_value: |
46 |
| - fish.weights = maximum_weight_value |
47 |
| - |
48 |
| - # calculates vector of instintict moviments |
49 |
| - distance_variations_sum = [0 for i in range(0, dimensions)] |
50 |
| - fitness_variations_sum = sum(fitness_variations) |
51 |
| - for fish in self.population: |
52 |
| - |
53 |
| - for i in range(0, dimensions): |
54 |
| - distance_variations = abs(fish.current_position[i] - fish.previous_position[i]) |
55 |
| - distance_variations_sum[i] = distance_variations_sum[i] + (distance_variations * fitness_variations[i]) |
56 |
| - |
57 |
| - instintive_movement_array = [] |
58 |
| - for i in range(0, dimensions): |
59 |
| - if fitness_variations_sum != 0: |
60 |
| - instintive_movement_array.append(distance_variations_sum[i]/fitness_variations_sum) |
61 |
| - else: |
62 |
| - instintive_movement_array.append(0) |
63 |
| - |
64 |
| - # executes instintive moviments |
65 |
| - for fish in self.population: |
66 |
| - for i in range(0, dimensions): |
67 |
| - fish.current_position[i] = fish.current_position[i] + instintive_movement_array[i] |
68 |
| - |
69 |
| - # calculates the baricenter |
70 |
| - weights_sum = 0 |
71 |
| - for fish in self.population: |
72 |
| - weights_sum = fish.weights |
73 |
| - |
74 |
| - weights_sum_times_position = 0 |
75 |
| - for fish in self.population: |
76 |
| - for i in range(0, dimensions): |
77 |
| - weights_sum_times_position = weights_sum_times_position + (fish.current_position[i] * fish.weights) |
78 |
| - |
79 |
| - baricenter = [weights_sum_times_position / weights_sum for i in range(0, dimensions)] |
80 |
| - |
81 |
| - # executes volitive moviment |
82 |
| - for fish in self.population: |
83 |
| - distance_to_baricenter = self._euclidian_distance(fish.current_position, baricenter) |
84 |
| - |
85 |
| - volational_array = [] |
86 |
| - difference_to_baricenter = [] |
87 |
| - weight_variation_sum = 0 |
88 |
| - for i in range(0, dimensions): |
89 |
| - volational_array.append(2 * fish.current_position[i]) |
90 |
| - difference_to_baricenter.append(fish.current_position[i] - baricenter[i]) |
91 |
| - weight_variation_sum = weight_variation_sum + abs(fish.weights - fish.previous_weight) |
92 |
| - |
93 |
| - sign = functools.partial(math.copysign, 1) |
94 |
| - for i in range(0, dimensions): |
95 |
| - fish.current_position[i] = fish.current_position[i] + -sign(weight_variation_sum) * volational_array[i] * random.random() * difference_to_baricenter[i] / distance_to_baricenter |
96 |
| - |
97 |
| - for fish in self.population: |
98 |
| - for i in range(0, dimensions): |
99 |
| - fish.current_position[i] -= individual_step_dacay |
100 |
| - |
101 |
| - for fish in self.population: |
102 |
| - fish.aply_function_on_current_position() |
103 |
| - |
104 |
| - bests.append(min([fish.fitness for fish in self.population])) |
105 |
| - return bests |
106 |
| - |
107 |
| - |
108 |
| - def _initialize_particles(self): |
109 |
| - self.population = [] |
110 |
| - for i in range(num_of_individuos): |
111 |
| - random_position = [self._get_random_number() for index in range(dimensions)] |
112 |
| - fish = Fish(self.function, random_position, random.uniform(300, 600)) |
113 |
| - self.population.append(fish) |
114 |
| - |
115 |
| - def _euclidian_distance(self, particle_i, particle_j): |
116 |
| - total = 0 |
117 |
| - for i in range(dimensions): |
118 |
| - distance = (particle_i[i] - particle_j[i])**2 |
119 |
| - total += distance |
120 |
| - return math.sqrt(total) |
| 34 | + self._initialize_cluster() |
| 35 | + |
| 36 | + for i in range(self.iterations_number): |
| 37 | + self.evaluate_cluster() |
| 38 | + self.updates_optimal_solution() |
| 39 | + |
| 40 | + self.apply_individual_movement() |
| 41 | + self.evaluate_cluster() |
| 42 | + self.updates_optimal_solution() |
| 43 | + |
| 44 | + self.apply_feeding() |
| 45 | + |
| 46 | + self.apply_instintive_collective_movement() |
| 47 | + self.apply_collective_volitive_movement() |
| 48 | + |
| 49 | + self.update_step(i) |
| 50 | + self.update_total_weight() |
| 51 | + |
| 52 | + self.evaluate_cluster() |
| 53 | + self.updates_optimal_solution() |
| 54 | + self.list_global_best_values.append(self.global_best) |
| 55 | + print("iter: {} = cost: {}".format(i, self.global_best)) |
| 56 | + |
| 57 | + def update_total_weight(self): |
| 58 | + self.total_weight = sum([fish.weight for fish in self.cluster]) |
| 59 | + |
| 60 | + def _initialize_cluster(self): |
| 61 | + self.cluster = [] |
| 62 | + for _ in range(self.num_of_individuos): |
| 63 | + fish = Fish( |
| 64 | + positions=[self._get_random_number() for _ in range(dimensions)], |
| 65 | + objective_function=self.function |
| 66 | + ) |
| 67 | + self.cluster.append(fish) |
| 68 | + |
| 69 | + def evaluate_cluster(self): |
| 70 | + for fish in self.cluster: |
| 71 | + fish.evaluate() |
| 72 | + |
| 73 | + def updates_optimal_solution(self): |
| 74 | + for fish in self.cluster: |
| 75 | + if fish.fitness < self.global_best: |
| 76 | + self.global_best = fish.fitness |
| 77 | + self.global_best_position = list(fish.current_position) |
| 78 | + |
| 79 | + def apply_individual_movement(self): |
| 80 | + for fish in self.cluster: |
| 81 | + fish.update_position_individual_movement(self.step_ind) |
| 82 | + |
| 83 | + def apply_feeding(self): |
| 84 | + max_delta_fitness = max([fish.delta_fitness for fish in self.cluster]) |
| 85 | + for fish in self.cluster: |
| 86 | + fish.feed(max_delta_fitness) |
| 87 | + |
| 88 | + def apply_instintive_collective_movement(self): |
| 89 | + sum_delta_fitness = sum([fish.delta_fitness for fish in self.cluster]) |
| 90 | + |
| 91 | + for fish in self.cluster: |
| 92 | + fish.update_position_collective_movement(sum_delta_fitness) |
| 93 | + |
| 94 | + def _calculate_barycenter(self): |
| 95 | + sum_weights = sum([fish.weight for fish in self.cluster]) |
| 96 | + sum_position_and_weights = [[x * fish.weight for x in fish.current_position] for fish in self.cluster] |
| 97 | + sum_position_and_weights = np.sum(sum_position_and_weights, 0) |
| 98 | + return [s / sum_weights for s in sum_position_and_weights] |
| 99 | + |
| 100 | + def apply_collective_volitive_movement(self): |
| 101 | + barycenter = self._calculate_barycenter() |
| 102 | + current_total_weight = sum([fish.weight for fish in self.cluster]) |
| 103 | + search_operator = -1 if current_total_weight > self.total_weight else 1 |
| 104 | + for fish in self.cluster: |
| 105 | + fish.update_position_volitive_movement(barycenter, self.step_vol, search_operator) |
| 106 | + |
| 107 | + def update_step(self, current_i): |
| 108 | + self.step_ind = self.initial_step_ind - current_i * float( |
| 109 | + self.initial_step_ind - self.final_step_ind) / iterations_number |
| 110 | + self.step_vol = self.initial_step_vol - current_i * float( |
| 111 | + self.initial_step_vol - self.final_step_vol) / iterations_number |
121 | 112 |
|
122 | 113 | def _get_random_number(self):
|
123 |
| - return ( |
124 |
| - self.function.lower_bound + random.uniform(0, 1) * (self.function.upper_bound - self.function.lower_bound) |
125 |
| - ) |
| 114 | + return np.random.uniform(self.function.lower_bound, self.function.upper_bound) |
0 commit comments