Алгоритм поиска всех последовательностей матрицы смежности через Depth First Search (DFS)
This commit is contained in:
parent
c1e7882cbb
commit
ea742b26d7
2 changed files with 126 additions and 14 deletions
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"cadFilePath":"",
|
"cadFilePath":"/home/idontsudo/framework/geometric_feasibility_predicate/cubes.FCStd",
|
||||||
"outPath":""
|
"outPath":"/home/idontsudo/framework/geometric_feasibility_predicate/out/"
|
||||||
}
|
}
|
|
@ -1,11 +1,112 @@
|
||||||
# Алгоритм генерации графа И/ИЛИ c помощью вычисления матрицы смежности
|
|
||||||
import FreeCAD as App
|
import FreeCAD as App
|
||||||
import uuid
|
import uuid
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
from typing import List, Dict, Any, TypeVar, Callable, Type, cast
|
from typing import List, Dict, Any, TypeVar, Callable, Type, cast
|
||||||
|
from itertools import repeat
|
||||||
|
|
||||||
|
|
||||||
|
def isInListRange(listIn, index):
|
||||||
|
try:
|
||||||
|
listIn[index]
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class AllSequences:
|
||||||
|
all_sequences = None
|
||||||
|
adj_matrix = None
|
||||||
|
topologyIds = None
|
||||||
|
adj_matrix_names = None
|
||||||
|
|
||||||
|
def __init__(self, adj_matrix) -> None:
|
||||||
|
self.adj_matrix = adj_matrix
|
||||||
|
self.all_possible_sequences(self.adj_matrix)
|
||||||
|
self.matrix_by_name()
|
||||||
|
pass
|
||||||
|
|
||||||
|
def matrix_by_name(self):
|
||||||
|
result = self.all_sequences
|
||||||
|
inc = 0
|
||||||
|
for matrix in self.all_sequences:
|
||||||
|
for index in range(len(matrix)):
|
||||||
|
result[inc][index] = list(filter(lambda el: el.get(
|
||||||
|
'number') == matrix[index]+1, self.topologyIds))[0].get('name')
|
||||||
|
inc += 1
|
||||||
|
self.adj_matrix_names = result
|
||||||
|
pass
|
||||||
|
|
||||||
|
def find_all_sequences(self, adj_matrix):
|
||||||
|
sequences = []
|
||||||
|
num_vertices = len(adj_matrix)
|
||||||
|
|
||||||
|
def dfs(vertex, sequence):
|
||||||
|
sequence.append(vertex)
|
||||||
|
|
||||||
|
if len(sequence) == num_vertices:
|
||||||
|
sequences.append(sequence)
|
||||||
|
return
|
||||||
|
|
||||||
|
for i in range(num_vertices):
|
||||||
|
if adj_matrix[vertex][i] == 1 and i not in sequence:
|
||||||
|
dfs(i, sequence.copy())
|
||||||
|
|
||||||
|
for i in range(num_vertices):
|
||||||
|
dfs(i, [])
|
||||||
|
|
||||||
|
self.all_sequences = sequences
|
||||||
|
|
||||||
|
def findId(self, listMatrix, id):
|
||||||
|
def filter_odd_num(in_num):
|
||||||
|
if in_num['name'] == id:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return list(filter(filter_odd_num, listMatrix))[0]['number']
|
||||||
|
|
||||||
|
def iter_paths(self, adj, min_length=6, path=None):
|
||||||
|
if not path:
|
||||||
|
for start_node in range(len(adj)):
|
||||||
|
yield from self.iter_paths(adj, min_length, [start_node])
|
||||||
|
else:
|
||||||
|
if len(path) >= min_length:
|
||||||
|
yield path
|
||||||
|
if path[-1] in path[:-1]:
|
||||||
|
return
|
||||||
|
current_node = path[-1]
|
||||||
|
for next_node in range(len(adj[current_node])):
|
||||||
|
if adj[current_node][next_node] == 1:
|
||||||
|
yield from self.iter_paths(adj, min_length, path + [next_node])
|
||||||
|
|
||||||
|
def allUnique(self, x):
|
||||||
|
seen = set()
|
||||||
|
return not any(i in seen or seen.add(i) for i in x)
|
||||||
|
|
||||||
|
def all_possible_sequences(self, matrix):
|
||||||
|
topologyIds = []
|
||||||
|
topologyMatrixNumber = {}
|
||||||
|
inc = 0
|
||||||
|
for k, v in matrix.items():
|
||||||
|
inc += 1
|
||||||
|
topologyIds.append({"name": k, "number": inc})
|
||||||
|
inc = 0
|
||||||
|
for k, v in matrix.items():
|
||||||
|
inc += 1
|
||||||
|
topologyMatrixNumber[inc] = list(
|
||||||
|
map(lambda el: self.findId(topologyIds, el), v))
|
||||||
|
self.topologyIds = topologyIds
|
||||||
|
adj = []
|
||||||
|
matrixSize = matrix.keys().__len__()
|
||||||
|
inc = 0
|
||||||
|
for k, v in topologyMatrixNumber.items():
|
||||||
|
adj.append(list(repeat(0, matrixSize)))
|
||||||
|
for el in v:
|
||||||
|
adj[inc][el-1] = 1
|
||||||
|
inc += 1
|
||||||
|
return self.find_all_sequences(adj)
|
||||||
|
|
||||||
|
|
||||||
# вспомогательный класс для работы с FreeCad API
|
|
||||||
class FreeCadRepository:
|
class FreeCadRepository:
|
||||||
_solids = []
|
_solids = []
|
||||||
|
|
||||||
|
@ -59,8 +160,10 @@ def to_class(c: Type[T], x: Any) -> dict:
|
||||||
return cast(Any, x).to_dict()
|
return cast(Any, x).to_dict()
|
||||||
|
|
||||||
# Вспомогательный класс который делает генрацию JSON на основе пайтон обьектов
|
# Вспомогательный класс который делает генрацию JSON на основе пайтон обьектов
|
||||||
|
|
||||||
|
|
||||||
class AdjacencyMatrix:
|
class AdjacencyMatrix:
|
||||||
matrixError: Dict[str,str] = {}
|
matrixError: Dict[str, str] = {}
|
||||||
all_parts: List[str]
|
all_parts: List[str]
|
||||||
first_detail: str
|
first_detail: str
|
||||||
matrix: Dict[str, List[str]]
|
matrix: Dict[str, List[str]]
|
||||||
|
@ -77,17 +180,19 @@ class AdjacencyMatrix:
|
||||||
if el == self.first_detail:
|
if el == self.first_detail:
|
||||||
return i
|
return i
|
||||||
i = +1
|
i = +1
|
||||||
|
|
||||||
def validateMatrix(self):
|
def validateMatrix(self):
|
||||||
for el in self.all_parts:
|
for el in self.all_parts:
|
||||||
if(self.matrix.get(el) == None):
|
if (self.matrix.get(el) == None):
|
||||||
self.matrixError[el] = 'Not found adjacency ' + el
|
self.matrixError[el] = 'Not found adjacency ' + el
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dict(obj: Any) -> 'AdjacencyMatrix':
|
def from_dict(obj: Any) -> 'AdjacencyMatrix':
|
||||||
assert isinstance(obj, dict)
|
assert isinstance(obj, dict)
|
||||||
all_pars = from_list(from_str, obj.get("allPars"))
|
all_pars = from_list(from_str, obj.get("allPars"))
|
||||||
first_detail = from_str(obj.get("firstDetail"))
|
first_detail = from_str(obj.get("firstDetail"))
|
||||||
matrix = from_dict(lambda x: from_list(from_str, x), obj.get("matrix"))
|
matrix = from_dict(lambda x: from_list(from_str, x), obj.get("matrix"))
|
||||||
|
|
||||||
return AdjacencyMatrix(all_pars, first_detail, matrix)
|
return AdjacencyMatrix(all_pars, first_detail, matrix)
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
|
@ -96,7 +201,7 @@ class AdjacencyMatrix:
|
||||||
result["firstDetail"] = from_str(self.first_detail)
|
result["firstDetail"] = from_str(self.first_detail)
|
||||||
result["matrix"] = from_dict(
|
result["matrix"] = from_dict(
|
||||||
lambda x: from_list(from_str, x), self.matrix)
|
lambda x: from_list(from_str, x), self.matrix)
|
||||||
if(self.matrixError.values().__len__() == 0):
|
if (self.matrixError.values().__len__() == 0):
|
||||||
result['matrixError'] = None
|
result['matrixError'] = None
|
||||||
else:
|
else:
|
||||||
result['matrixError'] = self.matrixError
|
result['matrixError'] = self.matrixError
|
||||||
|
@ -120,7 +225,9 @@ def adjacency_matrix_from_dict(s: Any) -> AdjacencyMatrix:
|
||||||
def adjacency_matrix_to_dict(x: AdjacencyMatrix) -> Any:
|
def adjacency_matrix_to_dict(x: AdjacencyMatrix) -> Any:
|
||||||
return to_class(AdjacencyMatrix, x)
|
return to_class(AdjacencyMatrix, x)
|
||||||
|
|
||||||
# Вспомогательный класс для работы с Freecad
|
# Вспомогательный класс для работы с Freecad
|
||||||
|
|
||||||
|
|
||||||
class FreeCadMetaModel(object):
|
class FreeCadMetaModel(object):
|
||||||
|
|
||||||
def __init__(self, label, vertex) -> None:
|
def __init__(self, label, vertex) -> None:
|
||||||
|
@ -329,7 +436,8 @@ class CadAdjacencyMatrix:
|
||||||
first_detail=GetFirstDetailUseCase().call(),
|
first_detail=GetFirstDetailUseCase().call(),
|
||||||
matrix=matrix,
|
matrix=matrix,
|
||||||
)
|
)
|
||||||
# Матрица основанная на соприкосновении обьектов
|
# Матрица основанная на соприкосновении обьектов
|
||||||
|
|
||||||
def matrixBySurfaces(self):
|
def matrixBySurfaces(self):
|
||||||
matrix = {}
|
matrix = {}
|
||||||
for part in FreeCadRepository().getAllSolids():
|
for part in FreeCadRepository().getAllSolids():
|
||||||
|
@ -347,6 +455,7 @@ class CadAdjacencyMatrix:
|
||||||
matrix=matrix
|
matrix=matrix
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
env = FS.readJSON('env.json')
|
env = FS.readJSON('env.json')
|
||||||
cadFile = env['cadFilePath']
|
cadFile = env['cadFilePath']
|
||||||
|
@ -354,12 +463,15 @@ def main():
|
||||||
if (cadFile == None):
|
if (cadFile == None):
|
||||||
return TypeError('CadFile not found env.json')
|
return TypeError('CadFile not found env.json')
|
||||||
App.open(u'' + cadFile)
|
App.open(u'' + cadFile)
|
||||||
|
|
||||||
# Получение матрицы
|
# Получение матрицы
|
||||||
matrixOut = CadAdjacencyMatrix().primitiveMatrix().to_dict()
|
topologyMatrix = CadAdjacencyMatrix().primitiveMatrix()
|
||||||
import json
|
import json
|
||||||
# Запись результата
|
sequences = json.dumps({"sequences": AllSequences(
|
||||||
FS.writeFile(json.dumps(matrixOut, ensure_ascii=False, indent=4), outPath,'out.json')
|
topologyMatrix.matrix).adj_matrix_names}, ensure_ascii=False, indent=4)
|
||||||
|
FS.writeFile(sequences, outPath, 'sequences.json')
|
||||||
|
FS.writeFile(json.dumps(topologyMatrix.to_dict(),
|
||||||
|
ensure_ascii=False, indent=4), outPath, 'adjacency_matrix.json')
|
||||||
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue