-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerator.py
213 lines (188 loc) · 7.92 KB
/
generator.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
from random import randint
from math import comb, ceil
from GraphAn import Graph, Analysis
'''
A class that is responsible for creating a supergraph
and subgraph in accordance with the specified condition of isomorphic embedding
'''
class Generator:
def __init__(self):
self.supergraph: Graph = None
self.subgraph: Graph = None
self.edgesCount: list = None
self.cuttingSub: dict = None
self.analysis: Analysis = None
self.embeddingCondition: bool = None
'''
Method for getting a value of type Int from the user
'''
@staticmethod
def inputNum(request, max = None):
while True:
inp = input(f"{request}: ")
if inp.isnumeric():
if max is None:
return int(inp)
elif max is not None and int(inp) < max:
return int(inp)
'''
Method for getting a one-character string from the user
'''
@staticmethod
def inputChar(request):
while True:
inp = input(f"{request}: ")
if inp.isalpha() and len(inp) == 1:
return inp.upper()
'''
Method for converting user input to a value of type Bool
'''
@staticmethod
def stringToBool(request, condTrue, condFalse):
while True:
inp = input(f"{request}: ")
if inp.lower() == condTrue.lower():
return True
elif inp.lower() == condFalse.lower():
return False
'''
Method for generating the number of incident edges for each vertex
'''
def generateEdges(self, size, nullVertex):
totalSum = comb(size, 2)
generatedSum = 0
edgesCount = []
for i in range(0, size):
if nullVertex:
edgesCount.append(randint(0, size))
generatedSum += edgesCount[i]
else:
edgesCount.append(randint(1, size))
generatedSum += edgesCount[i]
if generatedSum > totalSum:
scale = generatedSum / totalSum
generatedSum = 0
for i in range(0, size):
edgesCount[i] = ceil(edgesCount[i] / scale)
generatedSum += edgesCount[i]
while generatedSum != totalSum:
vrtx = randint(0, size - 1)
if generatedSum < totalSum:
if edgesCount[vrtx] < size:
edgesCount[vrtx] += 1
generatedSum += 1
else:
if edgesCount[vrtx] > 1:
edgesCount[vrtx] -= 1
generatedSum -= 1
self.edgesCount = edgesCount
'''
The method responsible for generating of the supergraph
'''
def generateSupergraph(self, size, nullVertex, gSymbol, vSymbol, eSymbol):
self.generateEdges(size, nullVertex)
graph = {}
for i in range(1, size + 1):
graph[f"{vSymbol.lower()}{i}"] = []
while len(graph[f"{vSymbol.lower()}{i}"]) != self.edgesCount[i-1]:
vertex = f"{vSymbol.lower()}{randint(1, size)}"
if vertex not in graph[f"{vSymbol.lower()}{i}"]:
graph[f"{vSymbol.lower()}{i}"].append(vertex)
self.supergraph = Graph(graph,
gSymbol.upper(), vSymbol.upper(), eSymbol.upper())
'''
A method that creates a substitution according to the generated set of vertices to be removed.
'''
def cutGraph(self, size, vSymbol):
toDelete = []
while len(toDelete) != self.supergraph.size - size:
vertexToDelete = f"{self.supergraph.vertex.lower()}{randint(1, size)}"
if vertexToDelete not in toDelete:
toDelete.append(vertexToDelete)
sub = {}
for index, vertex in enumerate(filter(lambda vertex: vertex not in toDelete, self.supergraph.graph)):
sub[vertex] = f"{vSymbol.lower()}{index + 1}"
self.cuttingSub = sub
'''
A method that additionally truncates the set of edges (used if the subgraph must be isomorphically nested)
'''
def reduceGraph(self, gSymbol, vSymbol, eSymbol):
graph = {}
for vertex1 in self.cuttingSub:
graph[self.cuttingSub[vertex1]] = []
edgeDeleteCount = int(len(self.supergraph.graph[vertex1]) / 3)
for vertex2 in self.supergraph.graph[vertex1]:
if vertex2 in self.cuttingSub:
edgeStatus = False
if edgeDeleteCount > 0:
edgeStatus = randint(0, 1)
if edgeStatus:
edgeDeleteCount -= 1
if not edgeStatus:
graph[self.cuttingSub[vertex1]].append(self.cuttingSub[vertex2])
self.subgraph = Graph(graph,
gSymbol.upper(), vSymbol.upper(), eSymbol.upper())
'''
A method that adds edges to the formed subgraph to violate condition B of Theorem 1 in the resulting substitutions
'''
def enlargeGraph(self, gSymbol, vSymbol, eSymbol):
while True:
self.reduceGraph(gSymbol, vSymbol, eSymbol)
self.analysis = Analysis(self.subgraph, self.supergraph,
"", False, False)
self.analysis.makeAnalysis()
for sub in self.analysis.completeSubs:
if self.analysis.conditionB(sub):
canBeConnectedFrom = list(
filter(lambda vrtx:
self.subgraph.hd[vrtx][0] < self.supergraph.hd[sub[vrtx]][0],
sub.keys()))
for vrtxFrom in canBeConnectedFrom[-1::-1]:
canBeConnectedTo = list(
filter(lambda v:
v not in self.subgraph.graph[vrtxFrom] and
sub[v] not in self.supergraph.graph[sub[vrtxFrom]]
and self.subgraph.hd[v][1] < self.supergraph.hd[sub[v]][1],
sub.keys()))
if len(canBeConnectedTo) > 0:
self.subgraph.graph[vrtxFrom].append(canBeConnectedTo[0])
break
self.analysis.printDetails = False
if self.analysis.makeAnalysis() == 3:
return 1
'''
The method responsible for forming a subgraph according to the isomorphic embedding condition
'''
def generateSubgraph(self, size, gSymbol, vSymbol, eSymbol):
self.cutGraph(size, vSymbol)
if self.embeddingCondition:
self.reduceGraph(gSymbol, vSymbol, eSymbol)
else:
self.enlargeGraph(gSymbol, vSymbol, eSymbol)
'''
A method that automatically generates a variant (supergraph and subgraph) and makes a PDF report of the analysis
'''
def createVariant(self):
g1Size = self.inputNum("Введіть розмірність надграфа")
g1Symbol = self.inputChar("Введіть позначення надграфа")
v1Symbol = self.inputChar("Введіть позначення множини вершин надграфа")
e1Symbol = self.inputChar("Введіть позначення множини ребер надграфа")
nullVrtx = self.stringToBool("Чи може вершина не містити можливих переходів?"
"(\"Так\", або \"Ні\")", "Так", "Ні")
self.generateSupergraph(g1Size, nullVrtx, g1Symbol, v1Symbol, e1Symbol)
self.embeddingCondition = self.stringToBool("Чи повинен підграф вкладатися?"
"(\"Так\", або \"Ні\")",
"Так", "Ні")
g2Size = self.inputNum("Введіть розмірність підграфа", g1Size)
g2Symbol = self.inputChar("Введіть позначення підграфа")
v2Symbol = self.inputChar("Введіть позначення множини вершин підграфа")
e2Symbol = self.inputChar("Введіть позначення множини ребер підграфа")
self.generateSubgraph(g2Size, g2Symbol, v2Symbol, e2Symbol)
fileName = "variant" + str(self.inputNum("Введіть номер варіанту"))
print("Надграф:")
print(self.supergraph.graph)
print("Підграф:")
print(self.subgraph.graph)
self.analysis = Analysis(self.subgraph, self.supergraph,
fileName, True, False)
self.analysis.makeAnalysis()