Алгоритм поиска всех последовательностей матрицы смежности через Depth First Search (DFS)

This commit is contained in:
IDONTSUDO 2023-07-13 19:55:18 +00:00 committed by Igor Brylyov
parent c1e7882cbb
commit ea742b26d7
2 changed files with 126 additions and 14 deletions

View file

@ -1,4 +1,4 @@
{ {
"cadFilePath":"", "cadFilePath":"/home/idontsudo/framework/geometric_feasibility_predicate/cubes.FCStd",
"outPath":"" "outPath":"/home/idontsudo/framework/geometric_feasibility_predicate/out/"
} }

View file

@ -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,6 +160,8 @@ 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]
@ -77,10 +180,12 @@ 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)
@ -121,6 +226,8 @@ 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:
@ -330,6 +437,7 @@ class CadAdjacencyMatrix:
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']
@ -356,10 +465,13 @@ def main():
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()