-
Notifications
You must be signed in to change notification settings - Fork 0
/
optimizationproblem.py
234 lines (177 loc) · 9.8 KB
/
optimizationproblem.py
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Oct 5 10:18:56 2022
@author: carlos
"""
import random
import solutionConfig as solCnf
import optimizationConfig as optCnf
from solution import Solution
import random
import networkx as nx
from solutionspace import SolutionSpace
from solutionspace import PopulationElement
from typing import List
from typing import Set
from log import Log
from infrastructure import Infrastructure
import numpy
class OptimizationProblem:
#numberOfSolutions = None
solutionTemplate = None
#population = None
#solutionId=0 #autoincrement to identify the solutions in the population
def __init__(self, log: Log, randomseed:int, numSol: int = None, solTemp: dict = None, solInfr:dict = None) -> None:
# def __init__(self, numSol = None, solTemp = None, solInfr = None):
self.log = log
self.randomSeed = randomseed
if optCnf.randomReproducible4Optimization:
self.randomNG = numpy.random.RandomState(self.randomSeed)
else:
self.randomNG = numpy.random.RandomState()
if (numSol==None) and (solTemp == None) and (solInfr == None):
self.initCoordinator()
elif (isinstance(numSol,int) and isinstance(solTemp,dict) and isinstance(solInfr,dict)):
self.initWorker(numSol,solTemp,solInfr)
else:
#self.log.print("ERROR::::Argument type of class OptimizationProblem not correct")
print("ERROR::::Argument type of class OptimizationProblem not correct")
def selectRandomWorker(self, listworker: list) -> str:
return listworker[self.randomNG.randint(len(listworker))]
def initCoordinator(self) -> None:
solTempl=dict()
solTempl['numberOfNodes']=solCnf.numberOfNodes
solTempl['numberOfServices']=solCnf.numberOfServices
self.solutionTemplate = solTempl
self.numberOfSolutionsInWorker = optCnf.numberOfSolutionsInWorkers
self.solutionSpace = SolutionSpace(len(solCnf.objectivesFunctions),self.randomNG)
self.deployedInfr = Infrastructure()
netGeneratorStr = "nx.barabasi_albert_graph(n="+str(solCnf.numberOfNodes)+", m=2)"
#self.deployedInfr.setConfiguration('newage', solCnf.numberOfNodes, solCnf.numberOfServices, netGeneratorStr)
self.deployedInfr.setConfiguration('journal',solCnf.numberOfNodes,solCnf.numberOfServices,netGeneratorStr)
self.deployedInfr.deployScenario(False)
# domainConfiguration.initializeRandom(optCnf.randomSeeds)
# domainConfiguration.setRandomState(optCnf.randomSeeds)
# domainConfiguration.getConfiguration('')
# #changing default configuration
# domainConfiguration.TOTALNUMBEROFNODES = solCnf.numberOfNodes
# domainConfiguration.TOTALNUMBEROFAPPS = solCnf.numberOfServices
# domainConfiguration.func_NETWORKGENERATION = "nx.barabasi_albert_graph(n="+str(domainConfiguration.TOTALNUMBEROFNODES)+", m=2)"
#
#
# domainConfiguration.setRandomState(optCnf.randomSeeds)
# domainConfiguration.networkModel('n'+str(domainConfiguration.TOTALNUMBEROFNODES)+'-')
# domainConfiguration.appsGeneration()
# domainConfiguration.usersConnectionGeneration()
self.infrastructure4mqttJson = dict()
#En esta estructura dict metemos todos los datos que necesites low workers para calcular el fitness
#TODO considerar que las distancias tendrian que esr basadas en los tiempos de propagacion y transmision, es decir, calcular con el weigth del edge
#all the features of the infrastructure needed by the worker are included in infrastructure dictionary
self.infrastructure4mqttJson['Gdistances'] = self.deployedInfr.deviceDistances()
self.infrastructure4mqttJson['clientNodes'] = self.deployedInfr.getEdgesDevices()
#self.g_distances_with_cloud = self.deviceDistances(domainConfiguration.G) ## este tiene el cloud
#self.solutionSpace.createRandomPopulationCoordinator(self.solutionTemplate, self.infrastructure,optCnf.selfId4Worker)
def initWorker(self, numSol: int, solTemp: dict, solInfr: dict) -> None:
#self.numberOfSolutions = numSol
self.solutionSpace = SolutionSpace(len(solCnf.objectivesFunctions),self.randomNG)
self.solutionTemplate = solTemp
self.infrastructure4mqttJson=solInfr
self.solutionSpace.createRandomPopulationAndJoin(self.solutionTemplate, self.infrastructure4mqttJson,optCnf.selfId4Worker,numSol)
'''
The current population is joined with the solutions received from the workers. This solutions only have the fitnes
so new solutions elements are created and append to the population
'''
def joinToPopulation(self, workerId: str,solSet: List[dict]) -> None:
self.solutionSpace.createSolutionWithInputAndJoinWithCurrentPopulation(workerId,solSet)
'''
Created for the case of the FullMigration scenario (population distributed along workers). It is required because
a central copy of the solutions in the workers is required for analysis of the experiments porpouse. Not really
need to implement the framework, just for experimentation
'''
def joinToPopulationWithoutFronts(self, workerId: str,solSet: List[dict]) -> None:
self.solutionSpace.createSolutionWithInputAndAggregateWithCurrentPopulationWithoutClassifyingFronts(workerId,solSet)
def removeManyWorstSolutions(self, quantity: int) -> List[PopulationElement]:
return self.solutionSpace.removeSetOfWorstSolutions(quantity)
def removeOneWorstSolutionById(self, idSol: str, idWorker: str) -> bool:
return self.solutionSpace.removeSolution(idSol,idWorker)
def joinTwoPopulations(self,offspring: List[PopulationElement]) -> None:
self.solutionSpace.joinToThePopulation(offspring)
def evolveWithRemoteSolution(self,chromosome: List[List[int]]) -> List[PopulationElement]:
popElement = self.TournamentSelection()
solutions = popElement.getSolution().crossover(chromosome)
for sol in solutions:
if self.randomNG.random()<optCnf.mutationProbability:
sol.mutate()
sol.calculateFitness()
offspring = self.solutionSpace.createSubPopulation(solutions, optCnf.selfId4Worker)
return offspring
#
# def crossOverSolutions(self,chromosome):
#
# #think about if the new children are just joined with the current population in the local worker, increasing the size of the local population,
# #or they should replace other solutions in the local population, keeping always the same size in the local population but (maybe) removing solutions
# #that are classified in good fronts in the global population in the coordinator
# #ANSWER: we add it without removing. The role to remove solutions is in charge of the coordinator.
#
# offspring = list()
#
# oneSolution = Solution(self.solutionTemplate,self.infrastructure)
# #newSolutionElement = (idWorker, self.solutionId, oneSolution, 'active')
# firstNewSolutionElement = dict()
# firstNewSolutionElement['workerId']='local'
# firstNewSolutionElement['solutionId']=self.solutionId
# firstNewSolutionElement['solution']=oneSolution
# self.solutionId = self.solutionId+1
#
# oneSolution = Solution(self.solutionTemplate,self.infrastructure)
# #newSolutionElement = (idWorker, self.solutionId, oneSolution, 'active')
# secondNewSolutionElement = dict()
# secondNewSolutionElement['workerId']='local'
# secondNewSolutionElement['solutionId']=self.solutionId
# secondNewSolutionElement['solution']=oneSolution
# self.solutionId = self.solutionId+1
#
# popElement = self.TournamentSelection()
# secondFatherId = self.getSolutionId(popElement)
# secodFatherWorkerId = self.getWorkerId(popElement)
#
#
# #we search the solutionid in the list containing all the dictionaries, which element solutionid is the one to search
# secondChromosome= self.getSolutionChromosomeById(secondFatherId,secodFatherWorkerId)
#
# childChrom1, childChrom2 = self.twoPointServiceCrossover(chromosome, secondChromosome)
# firstNewSolutionElement['solution'].chromosome=childChrom1
# secondNewSolutionElement['solution'].chromosome=childChrom2
#
# firstNewSolutionElement['solution'].calculateFitness()
# secondNewSolutionElement['solution'].calculateFitness()
#
# offspring.append(firstNewSolutionElement)
# offspring.append(secondNewSolutionElement)
#
# return offspring
#
def getSolutionChromosomeById(self,solId: int, workerId: str) -> List[List[int]]:
populationElement,pos = self.solutionSpace.getPopulationElementBySolutionId(solId,workerId)
if populationElement==None:
return None
else:
return populationElement.getSolution().getChromosome()
# def incorporateSolutionIntoFront(self,sol):
# movingSolutions = list()
# movingSolutions.append(sol)
# self.shiftSolutionsToHigherFronts(movingSolutions,0)
def TournamentSelection(self) -> PopulationElement:
popEl1, popEl2 = self.solutionSpace.getRandomSolutions(2)
bestPopEl = self.solutionSpace.chooseBetter(popEl1,popEl2)
return bestPopEl
# we obtain their front and crowding
def getPopulationFitnessInJson(self) -> List[dict]:
return self.solutionSpace.fitness2json()
def getSolutionsFitnessInJson(self, peList: List[PopulationElement]) -> List[dict]:
return self.solutionSpace.fitness2json(peList)
def getSolutionSpace(self) -> SolutionSpace:
return self.solutionSpace
def getInfrastructure(self) -> Infrastructure:
return self.deployedInfr