Example #1
0
    def build(self, *, max_depth: Optional[int] = None) -> 'Search':
        """ Builds the search tree upto leaves, or an optional maximum depth.

        This method can be called repeatedly, with higher depth values, to further increase the depth of the tree.

        :param max_depth: optional maximum depth of search tree
        :return: the modified Search object.
        """
        if max_depth is None:
            self.manifold.build(criterion.Layer(-1))
        elif max_depth < 1:
            raise ValueError(
                f'Expected a positive integer for max_depth. Got {max_depth} instead.'
            )
        elif max_depth > self.depth:
            self.manifold.build_tree(criterion.MaxDepth(max_depth),
                                     criterion.Layer(-1))
        return self
Example #2
0
 def setUpClass(cls) -> None:
     np.random.seed(42)
     cls.data, _ = datasets.bullseye(n=1000, num_rings=2)
     cls.manifold: Manifold = Manifold(cls.data, 'euclidean')
     cls.manifold.build(
         criterion.MaxDepth(10),
         criterion.Layer(5),
     )
     cls.graph: Graph = cls.manifold.graphs[0]
     return
Example #3
0
    def test_neighbors(self):
        for dataset in [
                datasets.bullseye,
        ]:  # datasets.spiral_2d, datasets.tori, datasets.skewer, datasets.line]:
            data, labels = dataset()
            manifold = Manifold(data, 'euclidean').build(
                criterion.MaxDepth(12),
                criterion.Layer(8),
            )

            for cluster in manifold.graphs[0].clusters:
                potential_neighbors: List[Cluster] = [
                    c for c in manifold.graphs[0].clusters
                    if c.name != cluster.name
                ]
                argcenters: List[int] = [
                    c.argmedoid for c in potential_neighbors
                ]
                distances: List[float] = list(
                    cluster.distance_from(argcenters))
                radii: List[float] = [
                    cluster.radius + c.radius for c in potential_neighbors
                ]
                true_neighbors = {
                    c: d
                    for c, d, r in zip(potential_neighbors, distances, radii)
                    if d <= r
                }
                neighbors = {
                    edge.neighbor(cluster): edge.distance
                    for edge in manifold.graphs[0].edges_from(cluster)
                }

                extras = set(neighbors.keys()) - set(true_neighbors.keys())
                self.assertEqual(
                    0,
                    len(extras),
                    msg=
                    f'got extra neighbors: optimal, true {len(true_neighbors)}, actual {len(neighbors)}\n'
                    + "\n".join([
                        f"{c.name}, {cluster.radius + c.radius:.6f}"
                        for c in extras
                    ]))

                missed = set(true_neighbors.keys()) - set(neighbors.keys())
                self.assertEqual(
                    0,
                    len(missed),
                    msg=
                    f'missed some neighbors: optimal, true {len(true_neighbors)}, actual {len(neighbors)}\n'
                    + '\n'.join([
                        f'{c.name}, {cluster.radius + c.radius:.6f}'
                        for c in missed
                    ]))
        return
Example #4
0
    def test_pruned(self):
        manifold: Manifold = Manifold(self.data, 'euclidean').build(criterion.MaxDepth(10), criterion.Layer(8))
        graph = manifold.graphs[0]
        pruned_graph, subsumed_clusters = graph.pruned_graph

        self.assertLessEqual(pruned_graph.cardinality, graph.cardinality)
        self.assertSetEqual(set(pruned_graph.clusters), set(subsumed_clusters.keys()))
        for cluster, subsumed in subsumed_clusters.items():
            self.assertEqual(0, len(subsumed.intersection(set(pruned_graph.clusters))))
Example #5
0
    def test_dot_file(self):
        manifold: Manifold = Manifold(self.data, 'euclidean').build(criterion.MinRadius(0.2), criterion.Layer(7))
        graph: Graph = manifold.graphs[0]
        old_clusters: Set[Cluster] = {cluster for cluster in graph.clusters}
        old_edges: Set[Edge] = {edge for edge in graph.edges}

        dot_string = manifold.graphs[0].as_dot_string('bullseye_d7')

        graph = graph.from_dot_string(dot_string)
        new_clusters: Set[Cluster] = {cluster for cluster in graph.clusters}
        new_edges: Set[Edge] = {edge for edge in graph.edges}

        self.assertEqual(old_clusters, new_clusters, f'Found mismatch between old and new clusters.')
        self.assertEqual(old_edges, new_edges, f'Found mismatch between old and new edges.')
        return