|
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