-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode.py
More file actions
196 lines (156 loc) · 10.2 KB
/
code.py
File metadata and controls
196 lines (156 loc) · 10.2 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
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
from os import times
import sys
from datetime import datetime
from typing import Dict
import dimod
from dimod.reference.samplers.exact_solver import ExactSolver
from dwave.system import LeapHybridSampler
import pandas as pd
import dwave.inspector
from dwave.system.composites.embedding import EmbeddingComposite
from dwave.system import DWaveSampler, EmbeddingComposite
def addControl(controles, idControl, idIncidencia):
#Este método se dedica a relacionar las incidencias con los controles que la componen.
for i in controles.keys():
if i == idControl: #Si el control ya está en el diccionario, se anexiona el id de la nueva incidencia.
controles[i].append(int(idIncidencia))
return controles
controles[idControl] = [int(idIncidencia)] #Si el control no está en el diccionario, se crea una nueva entrada junto a la
#incidencia.
return controles
def createList(dataPath):
incidencias = {} #Las incidencias son las brechas de seguridad que surgen. El objetivo es seleccionar las incidencias
#justas y necesarias que gestionar.
#Cada entrada contiene la gravedad y el tiempo relacionado con la incidencia a la que corresponde la
#clave de acceso del diccionario.
controles = {} #Los controles son problemas específicos que componen las incidencias. Cuando se gestiona una incidencia,
#se resuelven todos los controles que la forman, y se solucionan para el resto de incidencias que tengan
#ese control. El objetivo es resolver todos los controles de forma que todas las ncidencias se resuelvan.
#El formato de este diccionario tiene como clave de acceso la id del control, y el contenido de la
#entrada contiene las ids de las incidencias del que forma parte.
dataframe = dataframe = pd.read_csv(path, names=['IdIncidencia', 'IdAmenaza', 'Amenaza', 'Gravedad', 'IdControl', 'Control', 'Tiempo'])
idInc = dataframe['IdIncidencia'] #El identificador de las incidencias.
idCon = dataframe['IdControl'] #El identificador de los controles.
grav = dataframe['Gravedad'] #La gravedad de la incidencia. Para este problema no lo usaremos.
tiem = dataframe['Tiempo'] #El tiempo que se necesita para gestionar la incidencia.
incidencias[int(idInc[0])] = {'gravedad': int(grav[0]), 'tiempo': int(tiem[0])}
controles = addControl(controles, idCon[0], int(idInc[0])) #Se inicializa la lista de incidencias con la primera fila.
for i in range(1, len(dataframe.values)):
if(idInc[i] != idInc[i-1]): #Comprueba que la incidencia es nueva o no comparando el id con el anterior.
#NOTA: Esto solo funciona si la lista está ordenada por incidencias.
incidencias[int(idInc[i])] = {'gravedad': int(grav[i]), 'tiempo': int(tiem[i])}
controles = addControl(controles, idCon[i], int(idInc[i]))
return incidencias, controles, dataframe
def createBQM(incidencias, controles):
idIncidencias = incidencias.keys() #Se extraen las ids de las incidencias para mejor gestión.
idControles = controles.keys() #Se extraen las ids de los controles para mejor gestión.
Q = dimod.AdjVectorBQM(dimod.Vartype.BINARY) #Este es el formato principal del BQM, una matriz cuadrática.
J = {} #Este formato se utiliza para usarlo con el inspector.
tiempos = [] #Se extraen los tiempos para mejor gestión y para sacar el máximo.
for i in idIncidencias:
tiempos.append(incidencias[i]['tiempo'])
penalizacion = max(tiempos) + 1 #La penalización es el valor que nos va a ayudar a seleccionar qué incidencias tenemos
#que seleccionar. La condición que necesitamos que se cumpla es que todos los controles
#sean resueltos. Cualquier solución que no cumpla con esa condición, será descartada
#gracias al valor de penalización. Se ha decidido que el valor sea el máximo tiempo
#entre todas las incidencias para que pueda variar según sea necesario, y es
#incrementado en 1 para que no interfiera con el peso de las decisiones.
#Término linear xi (-P*xi).
#Este término linear se encarga de relacionar el tiempo que se tarda en gestionar una incidencia. De forma muy simplificada,
#esto es lo que determinará qué incidencias son las mejores en caso de que haya varias soluciones válidas. Se recomienda leer
#la documentación para una explicación en mayor detalle y cómo se ha llegado a esta operación.
for i, j in zip(idIncidencias, range(len(idIncidencias))):
Q.set_linear(str(i), tiempos[j])
J[(i, i)] = tiempos[j]
print(J[(i,i)])
#Término linear xi (-P*xi).
#Esta parte se utiliza para restar la penalización a cada incidencia que resuelva un control. De forma muy simplificada, si
#una incidencia resuelve varios controles, es más probable que sea seleccionada. Se recomienda leer la documentación para
#una explicación en mayor detalle y cómo se ha llegado a esta operación.
for k in idControles:
cIncidencias = controles[k] #Se extraen todas las incidencias de las que forma parte cada control, de forma que se
#pueda usar para acceder al BQM.
for i in cIncidencias:
key = (str(i))
Q.linear[key] -= penalizacion
J[(i, i)] -= int(penalizacion)
print(J[i,i])
#Término cuadrático xi-xj (2P*xi*xj).
#Esta parte sirve simplemente para inicializar los términos cuadráticos en el BQM.
for i in range(len(idIncidencias)):
for j in range(i + 1, len(idIncidencias)):
incidencia1 = list(idIncidencias)[i]
incidencia2 = list(idIncidencias)[j]
key = (str(incidencia1), str(incidencia2))
Q.quadratic[key] = 0
J[(incidencia1, incidencia2)] = 0
#Término cuadrático xi-xj (2P*xi*xj).
#El término cuadrático se encarga de evitar redundancias entre los controles. De forma muy simplificada, si un control es
#resuelto por dos incidencias, puede ser que una de esas incidencias sea innecesaria. Se recomienda leer la documentación
#para una explicación en mayor detalle y cómo se ha llegado a esta operación.
for k in idControles:
cIncidencias = controles[k]
for i in range(len(cIncidencias)):
for j in range(i + 1, len(cIncidencias)):
incidencia1 = cIncidencias[i]
incidencia2 = cIncidencias[j]
key = (str(incidencia1), str(incidencia2))
Q.quadratic[key] += 2 * penalizacion
J[(incidencia1, incidencia2)] += 2 * penalizacion
print(J[(incidencia1, incidencia2)])
return Q, J
def solve_knapsack(incidencias, controles, online, sampler=None, samplerSpin=None):
timeBqmS = datetime.now()
bqm, J = createBQM(incidencias, controles) #Se crea la matriz con las energías entre cada incidencia.
timeBqmF = datetime.now()
timeBQM = timeBqmF - timeBqmS
print('Se han tardado ' + str(timeBQM) + ' segundos en crear el BQM.')
timeSamplerS = datetime.now()
if online:
sampler = LeapHybridSampler() #Se inicializa el sampler. El LeapHybridSampler se utiliza para conectarse a
else: #los ordenadores de D-Wave, y el ExactSolver para hacer una simulación en la
sampler = ExactSolver() #computadora.
timeSamplerF = datetime.now()
timeSampler = timeSamplerF - timeSamplerS
print('Se han tardado ' + str(timeSampler) + ' segundos en crear el sampler.')
timeSolverS = datetime.now()
sampleset = sampler.sample(bqm) #Se pasa el BQM que hemos creado anteriormnte al sampler y busca las soluciones.
timeSolverF = datetime.now()
timeSolver = timeSolverF - timeSolverS
print('Se han tardado ' + str(timeSolver) + ' segundos en resolver el problema.')
sample = sampleset.first.sample #Se guarda qué incidencias han sido gestionadas y cuáles no.
energy = sampleset.first.energy #Se guarda la energía que tiene la solución.
selected_item_ids = []
for varname, value in sample.items():
# For each "x" variable, check whether its value is set, which
# indicates that the corresponding item is included in the
# knapsack
# The index into the weight array is retrieved from the
# variable name
if(sample[varname] == 1):
selected_item_ids.append(int(varname))
return sorted(selected_item_ids), energy, timeSolver, sampleset, J
if __name__ == '__main__':
path = sys.argv[1] if len(sys.argv) > 1 else "/home/ismael/Escritorio/Cuantica/MVC/sample.csv"
if sys.argv[2].lower() != 'false' and str(sys.argv[2]).lower() != 'true':
print('Se ha introducido el modo del sampler incorrectamenete.\nRecuerde que para el sampler offline se utiliza "false" y para el online se utiliza "true".')
sys.exit()
if sys.argv[2].lower() == 'true':
online = True
else:
online = False
incidencias, controles, dataframe = createList(path)
timeTotalS = datetime.now()
selected_item_ids, energy, timeSolver, sampleset, J = solve_knapsack(incidencias, controles, online)
timeTotalF = datetime.now()
timeTotal = timeTotalF - timeTotalS
selected_time = list(dataframe.loc[selected_item_ids,'Tiempo'])
sampler = EmbeddingComposite(DWaveSampler(solver={'qpu': True}))
response = sampler.sample_qubo(J, num_reads=1000)
dwave.inspector.show(response)
# dwave.inspector.show(sampleset)
print("Encontrada solución con la energía {}".format(energy))
print("Items seleccionados (0-indexed):", selected_item_ids)
print("Tiempo total: ", timeTotal)
print("Tiempo de los objetos seleccionados: {}, Total = {}".format(selected_time, sum(selected_time)))
print(sampleset)