def test_binary_partition_tree_exponential_linkage_equiv(self): np.random.seed(10) g = hg.get_4_adjacency_graph((10, 10)) edge_weights = np.random.rand(g.num_edges()) edge_weight_weights = np.random.randint(1, 10, g.num_edges()) tree, altitudes = hg.binary_partition_tree_exponential_linkage( g, edge_weights, 0, edge_weight_weights) t_ref, alt_ref = hg.binary_partition_tree_average_linkage( g, edge_weights, edge_weight_weights) self.assertTrue(np.all(tree.parents() == t_ref.parents())) self.assertTrue(np.allclose(altitudes, alt_ref)) tree, altitudes = hg.binary_partition_tree_exponential_linkage( g, edge_weights, float('inf'), edge_weight_weights) t_ref, alt_ref = hg.binary_partition_tree_complete_linkage( g, edge_weights) self.assertTrue(np.all(tree.parents() == t_ref.parents())) self.assertTrue(np.allclose(altitudes, alt_ref)) tree, altitudes = hg.binary_partition_tree_exponential_linkage( g, edge_weights, float('-inf'), edge_weight_weights) t_ref, alt_ref = hg.binary_partition_tree_single_linkage( g, edge_weights) self.assertTrue(np.all(tree.parents() == t_ref.parents())) self.assertTrue(np.allclose(altitudes, alt_ref))
def binary_partition_tree_exponential_linkage(graph, edge_weights, alpha, edge_weight_weights=None): """ Binary partition tree with exponential linkage distance. Given a graph :math:`G=(V, E)`, with initial edge weights :math:`w` with associated weights :math:`w_2`, the distance :math:`d(X,Y)` between any two clusters :math:`X` and :math:`Y` is .. math:: d(X,Y) = \\frac{1}{Z} \sum_{x \in X, y \in Y, \{x,y\} in E} w_2(\{x,y\}) \\times \exp(\\alpha * w(\{x,y\})) \\times w(\{x,y\}) with :math:`Z = \sum_{x \in X, y \in Y, \{x,y\} \in E} w_2(\{x,y\}) \\times \exp(\\alpha * w(\{x,y\}))`. :See: Nishant Yadav, Ari Kobren, Nicholas Monath, Andrew Mccallum. `Supervised Hierarchical Clustering with Exponential Linkage <http://proceedings.mlr.press/v97/yadav19a.html>`_ Proceedings of the 36th International Conference on Machine Learning, PMLR 97:6973-6983, 2019. :param graph: input graph :param edge_weights: edge weights of the input graph :param alpha: exponential parameter :param edge_weight_weights: weighting of edge weights of the input graph (default to an array of ones) :return: a tree (Concept :class:`~higra.CptHierarchy`) and its node altitudes """ alpha = float(alpha) if edge_weight_weights is None: edge_weight_weights = np.ones_like(edge_weights) else: edge_weights, edge_weight_weights = hg.cast_to_common_type( edge_weights, edge_weight_weights) # special cases: improve efficiency and avoid numerical issues if alpha == 0: tree, altitudes = hg.binary_partition_tree_average_linkage( graph, edge_weights, edge_weight_weights) elif alpha == float('-inf'): tree, altitudes = hg.binary_partition_tree_single_linkage( graph, edge_weights) elif alpha == float('inf'): tree, altitudes = hg.binary_partition_tree_complete_linkage( graph, edge_weights) else: res = hg.cpp._binary_partition_tree_exponential_linkage( graph, edge_weights, alpha, edge_weight_weights) tree = res.tree() altitudes = res.altitudes() hg.CptHierarchy.link(tree, graph) return tree, altitudes
def test_binary_partition_tree_complete_linkage(self): graph = hg.get_4_adjacency_graph((3, 3)) edge_weights = np.asarray((1, 8, 2, 10, 15, 3, 11, 4, 12, 13, 5, 6), np.float32) tree, levels = hg.binary_partition_tree_complete_linkage( graph, edge_weights) expected_parents = np.asarray( (9, 9, 10, 11, 11, 12, 13, 13, 14, 10, 16, 12, 15, 14, 15, 16, 16), np.uint32) expected_levels = np.asarray( (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 13, 15), np.float32) self.assertTrue(np.all(expected_parents == tree.parents())) self.assertTrue(np.all(expected_levels == levels))
def CLINK(G): return hg.binary_partition_tree_complete_linkage(G[0], G[1])