def add_typing(self, source, target, mapping,
total=True, attrs=None):
"""Add homomorphism to the hierarchy."""
if source not in self.nodes():
raise HierarchyError(
"Node '%s' is not defined in the hierarchy!" % source)
if target not in self.nodes():
raise HierarchyError(
"Node '%s' is not defined in the hierarchy!" % target)
if (source, target) in self.edges():
raise HierarchyError(
"Edge '%s->%s' already exists in the hierarchy: "
"no muliple edges allowed!" %
(source, target)
)
if not isinstance(self.node[source], GraphNode):
if type(self.node[source]) == RuleNode:
raise HierarchyError(
"Source node is a rule, use `add_rule_typing` "
"method instead!"
)
else:
raise HierarchyError(
"Source of a typing should be a graph, `%s` is provided!" %
type(self.node[source])
)
if not isinstance(self.node[target], GraphNode):
raise HierarchyError(
"Target of a typing should be a graph, `%s` is provided!" %
type(self.node[target])
)
# check no cycles are produced
self.add_edge(source, target)
if not nx.is_directed_acyclic_graph(self):
self.remove_edge(source, target)
raise HierarchyError(
"Edge '%s->%s' creates a cycle in the hierarchy!" %
(source, target)
)
self.remove_edge(source, target)
# check if the homomorphism is valid
check_homomorphism(
self.node[source].graph,
self.node[target].graph,
mapping,
total=total
)
# check if newly created path commutes with existing shortest paths
self._check_consistency(source, target, mapping)
self.add_edge(source, target)
if attrs is not None:
normalize_attrs(attrs)
self.edge[source][target] = self.graph_typing_cls(
mapping, total, attrs)
self.typing[source][target] = self.edge[source][target].mapping
return
评论列表
文章目录