def get_intersection(graph1, graph2): result = Graph() result.vertices_count = graph1.vertices_count * graph2.vertices_count for i in graph1.start_vertices: for j in graph2.start_vertices: result.start_vertices.add(i * graph1.vertices_count + j) for i in graph1.terminal_vertices: for j in graph2.terminal_vertices: result.terminal_vertices.add(i * graph1.vertices_count + j) for label in graph1.label_matrices.keys(): if label in graph2.label_matrices.keys(): result.label_matrices[label] = graph1.label_matrices[ label].kronecker(graph2.label_matrices[label]) return result
def cfpq_tensor_product(graph: Graph, grammar: CFG): if graph.vertices_count == 0: return False result = graph.get_copy() rfa = Graph() rfa_heads = dict() rfa.vertices_count = sum( [len(production.body) + 1 for production in grammar.productions]) index = 0 for production in grammar.productions: start_state = index terminal_state = index + len(production.body) rfa.start_vertices.add(start_state) rfa.terminal_vertices.add(terminal_state) rfa_heads[(start_state, terminal_state)] = production.head.value for variable in production.body: matrix = rfa.label_matrices.get( variable.value, Matrix.sparse(BOOL, rfa.vertices_count, rfa.vertices_count)) matrix[index, index + 1] = True rfa.label_matrices[variable.value] = matrix index += 1 index += 1 for production in grammar.productions: if len(production.body) == 0: matrix = Matrix.sparse(BOOL, graph.vertices_count, graph.vertices_count) matrix += Matrix.identity(BOOL, graph.vertices_count) result.label_matrices[production.head] = matrix changed = True while changed: changed = False intersection = Utils.get_intersection(rfa, result) closure = Utils.get_transitive_closure_squaring(intersection) for i, j, _ in zip(*closure.to_lists()): rfa_from, rfa_to = i // result.vertices_count, j // result.vertices_count graph_from, graph_to = i % result.vertices_count, j % result.vertices_count if (rfa_from, rfa_to) not in rfa_heads: continue variable = rfa_heads[(rfa_from, rfa_to)] matrix = result.label_matrices.get( variable, Matrix.sparse(BOOL, graph.vertices_count, graph.vertices_count)) if matrix.get(graph_from, graph_to) is None: changed = True matrix[graph_from, graph_to] = True result.label_matrices[variable] = matrix return result.label_matrices.get( grammar.start_symbol, Matrix.sparse(BOOL, graph.vertices_count, graph.vertices_count))