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