Алгоритм поиска всех последовательностей матрицы смежности через 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":"",
"outPath":""
"cadFilePath":"/home/idontsudo/framework/geometric_feasibility_predicate/cubes.FCStd",
"outPath":"/home/idontsudo/framework/geometric_feasibility_predicate/out/"
}

View file

@ -1,11 +1,112 @@
# Алгоритм генерации графа И/ИЛИ c помощью вычисления матрицы смежности
import FreeCAD as App
import uuid
import os
import json
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:
_solids = []
@ -59,8 +160,10 @@ def to_class(c: Type[T], x: Any) -> dict:
return cast(Any, x).to_dict()
# Вспомогательный класс который делает генрацию JSON на основе пайтон обьектов
class AdjacencyMatrix:
matrixError: Dict[str,str] = {}
matrixError: Dict[str, str] = {}
all_parts: List[str]
first_detail: str
matrix: Dict[str, List[str]]
@ -77,10 +180,12 @@ class AdjacencyMatrix:
if el == self.first_detail:
return i
i = +1
def validateMatrix(self):
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
@staticmethod
def from_dict(obj: Any) -> 'AdjacencyMatrix':
assert isinstance(obj, dict)
@ -96,7 +201,7 @@ class AdjacencyMatrix:
result["firstDetail"] = from_str(self.first_detail)
result["matrix"] = from_dict(
lambda x: from_list(from_str, x), self.matrix)
if(self.matrixError.values().__len__() == 0):
if (self.matrixError.values().__len__() == 0):
result['matrixError'] = None
else:
result['matrixError'] = self.matrixError
@ -121,6 +226,8 @@ def adjacency_matrix_to_dict(x: AdjacencyMatrix) -> Any:
return to_class(AdjacencyMatrix, x)
# Вспомогательный класс для работы с Freecad
class FreeCadMetaModel(object):
def __init__(self, label, vertex) -> None:
@ -330,6 +437,7 @@ class CadAdjacencyMatrix:
matrix=matrix,
)
# Матрица основанная на соприкосновении обьектов
def matrixBySurfaces(self):
matrix = {}
for part in FreeCadRepository().getAllSolids():
@ -347,6 +455,7 @@ class CadAdjacencyMatrix:
matrix=matrix
)
def main():
env = FS.readJSON('env.json')
cadFile = env['cadFilePath']
@ -356,10 +465,13 @@ def main():
App.open(u'' + cadFile)
# Получение матрицы
matrixOut = CadAdjacencyMatrix().primitiveMatrix().to_dict()
topologyMatrix = CadAdjacencyMatrix().primitiveMatrix()
import json
# Запись результата
FS.writeFile(json.dumps(matrixOut, ensure_ascii=False, indent=4), outPath,'out.json')
sequences = json.dumps({"sequences": AllSequences(
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()