This repository was archived by the owner on Dec 10, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathembedding_solver.py
More file actions
118 lines (91 loc) · 4.4 KB
/
Copy pathembedding_solver.py
File metadata and controls
118 lines (91 loc) · 4.4 KB
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import logging
import random
from dataclasses import dataclass
from typing import Optional
from src.embedding.embedding import Embedding
from src.graph.undirected_graph import UndirectedGraphAdjList
from src.solver.initialization import Initialization
from src.solver.supernode_extension import SupernodeExtension
logger = logging.getLogger('evolution')
@dataclass
class EvolutionParams():
population_size: int
max_mutation_trials: int
mutation_extend_to_free_neighbors_probability: float
class EmbeddingSolver():
def __init__(self, H: UndirectedGraphAdjList, m, n, t):
self.H = H
if H.nodes_count < 2:
raise NameError('The minor to embed must have at least two nodes')
self._embedding = Embedding(H, m, n, t)
self.initialization = Initialization(self._embedding)
self._supernode_extension = SupernodeExtension(self._embedding)
def initialize_embedding(self):
self.initialization.init_dfs()
self._local_maximum()
def get_embedding(self):
return self._embedding.get_embedding(G_to_H_mapping=True)
def commit(self, playground: Embedding):
self._embedding = playground
self._supernode_extension = SupernodeExtension(self._embedding)
def generate_population_and_select(self, params: EvolutionParams) -> Optional[Embedding]:
"""Generates a new population & selects and returns the best individual
from it."""
population = self._generate_children(params)
if not population:
population = self.last_trial(params)
if not population:
logger.info(f'🔳 Population generation failed')
return None
if len(population) < params.population_size:
logger.info(f'🔳 {params.max_mutation_trials} mutations to construct '
' a new child failed, will return a smaller population: '
f'{len(population)}/{params.population_size}')
selected_population = self._select_best_child(population)
return selected_population
def last_trial(self, params: EvolutionParams) -> Optional[list[Embedding]]:
"""Try to remove unnecessary supernode nodes and generate a new population"""
logger.info(f'🔳 Last trial, remove redundant nodes')
self._embedding.remove_redundancy()
return self._generate_children(params)
def _generate_children(self, params: EvolutionParams) -> list[Embedding]:
"""Generates children (Embeddings) for one population."""
population = [] # list of Embeddings
for i in range(params.population_size):
child = self._generate_child(params, i)
if child:
population.append(child)
else:
# early return as it is unlikely that we will be able
# to generate more children
return population
return population
def _generate_child(self, params: EvolutionParams, child_number: int) -> Optional[Embedding]:
logger.info('')
logger.info(f'--- Try find a new viable mutation')
for _ in range(params.max_mutation_trials):
logger.info('--- MUTATION')
if random.random() < params.mutation_extend_to_free_neighbors_probability:
mutation = self._supernode_extension.extend_random_supernode_to_free_neighbors()
else:
mutation = self._supernode_extension.extend_random_supernode()
if mutation:
logger.info(f'💚 Valid mutation for child {child_number}')
return mutation
logger.info(f'🔳 All {params.max_mutation_trials} mutations failed, '
'could not construct a child -> Abort')
return None
def _select_best_child(self, population: list[Embedding]):
logger.info('')
logger.info('Select best child')
# Try to optimize to local maximum first
improvements = []
for i, child in enumerate(population):
logger.info(f'💚 Checking local optima for child {i}')
improvements.append(child.try_embed_missing_edges())
best_child_index = improvements.index(max(improvements))
return population[best_child_index]
def _local_maximum(self) -> int:
return self._embedding.try_embed_missing_edges()
def found_embedding(self) -> bool:
return self._embedding.is_valid_embedding()