File size: 2,393 Bytes
1c5e165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
#VERSIÓN 4: VERSIÓN SEMI-ORIENTADA A OBJETOS
#(F): A añadir en (F)uturas versiones

### FUNCIONES AUXILIARES ###

import random

from .Reparto import Reparto


def mejor_individuo(list_individuos : list[Reparto]) -> Reparto: #paralelizable
        mejor_individuo = list_individuos[0]
        for individuo in list_individuos[1:]: 
            mejor_individuo = individuo if individuo.coste < mejor_individuo.coste else mejor_individuo
        #print("mejor_individuo: ", mejor_individuo.ruta, mejor_individuo.coste)
        return mejor_individuo

class Evolucion:              

    @staticmethod
    def elitismo(poblacion : list[Reparto]) -> Reparto: #mejor ruta de la poblacion
        return mejor_individuo(poblacion)

    @staticmethod
    def torneo(poblacion : list[Reparto], tamano_torneo) -> list[Reparto]: #mejor ruta de una parte de la poblacion
        selected_individuos = random.sample(poblacion, tamano_torneo)
        return mejor_individuo(selected_individuos)

    @staticmethod
    def mutate(ruta : Reparto) -> Reparto: #intercambia dos posiciones en la ruta
        idx1, idx2 = random.sample(range(Reparto.grafo.num_nodos + Reparto.vehiculos.num_vehiculos - 2), 2) 
        lista = ruta.ruta.copy()
        lista[idx1], lista[idx2] = lista[idx2], lista[idx1]
        return Reparto(lista)

    @staticmethod
    def crossover(parent1 : Reparto, parent2 : Reparto) -> Reparto: #cruza dos rutas, pegando un cacho de la primera en la segunda
        num_total = Reparto.grafo.num_nodos + Reparto.vehiculos.num_vehiculos - 2
                                                                                        #-1 por el Almacén
                                                                                        #-1 porque si hay n vehiculos, solo añadimos n-1 simbolos

        start = random.randint(0, num_total - 1) #random.randint(a, b) toma un número entero al azar entre [a,b], no entre [a,b)
        end = random.randint(start, num_total - 1)

        child = [None] * num_total

        for i in range(start, end+1):
            child[i] = parent1.ruta[i]
        remaining = [item for item in parent2.ruta if item not in child]
        remaining_index = 0
        for i in range(num_total):
            if child[i] == None:
                child[i] = remaining[remaining_index]
                remaining_index += 1

        return Reparto(child)