Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix ultrametric opening and improve documentation #268

Merged
merged 1 commit into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions higra/algo/graph_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,35 @@ def ultrametric_open(graph, edge_weights):
Subdominant ultrametric of the given edge weighted graph.

The subdominant ultrametric relative to a given dissimilarity measure (here the graph edge weights)
is defined as the largest ultrametric smaller than the dissimilarity measure.
is defined as the largest ultrametric smaller than the given dissimilarity measure. The result is thus a
saliency map: new edge weights such that any upper thresholding of the edge weights will produce graph cut.

In the case of an edge weighted undirected graph, the value of the subdominant ultrametric on the
edge :math:`e_{xy}` is given by the min-max distance between :math:`x` and :math:`y`.
In the case of an edge weighted undirected graph, the value of the subdominant ultrametric :math:`u(e_{xy})` on the
edge :math:`e_{xy}` is given by the min-max distance between :math:`x` and :math:`y`:

Complexity: :math:`\mathcal{O}(n*log(n))` with :math:`n` the number of edges in the graph
.. math::

u(e_{xy}) = min_{p \in P_{xy}} max_{e \in p} w(e)

where :math:`P_{xy}` is the set of all paths between :math:`x` and :math:`y`.

This function is a morphological opening: it is increasing, idempotent and anti-extensive (with respect to :attr:`edge_weights`).

Complexity: :math:`\mathcal{O}(n*log(n))` with :math:`n` the number of edges in the graph.

:Example:

>>> graph = hg.get_4_adjacency_graph((3, 3))
>>> edge_weights = np.asarray((2, 3, 9, 5, 10, 1, 5, 8, 2, 2, 4, 3))
>>> hg.ultrametric_open(graph, edge_weights)
array([2, 3, 9, 3, 9, 1, 4, 3, 2, 2, 4, 3])

:param graph: Input graph
:param edge_weights: Graph edge weights
:param edge_weights: Graph edge weights (disimilarity measure)
:return: edge weights corresponding to the subdominant ultrametric
"""
tree, altitudes = hg.bpt_canonical(edge_weights, graph)
return hg.saliency(altitudes)
tree, altitudes = hg.bpt_canonical(graph, edge_weights)
return hg.saliency(tree, altitudes)


def minimum_spanning_tree(graph, edge_weights):
Expand Down
2 changes: 1 addition & 1 deletion test/python/test_algo/test_graph_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def test_adjacency_matrix_2_undirected_graph_sparse(self):
with self.assertRaises(ValueError):
hg.adjacency_matrix_2_undirected_graph(ref_adj_mat, non_edge_value=-1)

def ultrametric_open(self):
def test_ultrametric_open(self):
graph = hg.get_4_adjacency_graph((3, 3))
edge_weights = np.asarray((2, 3, 9, 5, 10, 1, 5, 8, 2, 2, 4, 3), dtype=np.int32)

Expand Down