File size: 3,253 Bytes
dbc8c36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"""
High-level utilities for Collatz operations.

This module provides glue functions used by the web interface (app.py),
combining steps such as:

  - generating an inverse Collatz tree,
  - generating the minimal subtree up to N,
  - computing basic statistics,
  - rendering graphs to Graphviz PNG images.
"""

from __future__ import annotations

from typing import Optional, Tuple
from pathlib import Path

import pandas as pd

from src.collatz.inverse_tree import generate_collatz_tree
from src.collatz.minimal_subtree import generate_minimal_collatz_subtree_edges
from src.visual.render import render_collatz_tree_graphviz
from src.collatz.metrics import compute_basic_graph_stats


def build_and_render_collatz_tree(
    backbone_length: int,
    branch_length: int,
    max_depth: int,
    *,
    filename: str = "collatz_tree",
    output_dir: Optional[str] = "outputs",
    return_edges: bool = False,
) -> Tuple[str, Optional[pd.DataFrame]]:
    """
    Generate an inverse Collatz tree, render it as a PNG image, and optionally
    return the underlying edge DataFrame.
    """

    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    df_edges: pd.DataFrame = generate_collatz_tree(
        backbone_length=backbone_length,
        branch_length=branch_length,
        max_depth=max_depth,
    )

    image_path = render_collatz_tree_graphviz(
        df_edges=df_edges,
        filename=filename,
        directory=output_path,
        image_format="png",
    )

    if return_edges:
        return image_path, df_edges

    return image_path, None


def build_and_render_minimal_subtree(
    N: int,
    *,
    filename: str = "collatz_minimal_subtree",
    output_dir: Optional[str] = "outputs",
    return_edges: bool = False,
) -> Tuple[str, Optional[pd.DataFrame]]:
    """
    Generate the minimal Collatz subtree containing all integers 1..N,
    render it as a PNG image, and optionally return the underlying
    edge DataFrame.

    This uses the structural branch construction (Algorithms 5 and 6)
    implemented in `generate_minimal_collatz_subtree_edges`.
    """

    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    df_edges: pd.DataFrame = generate_minimal_collatz_subtree_edges(N)

    image_path = render_collatz_tree_graphviz(
        df_edges=df_edges,
        filename=filename,
        directory=output_path,
        image_format="png",
    )

    if return_edges:
        return image_path, df_edges

    return image_path, None


def compute_collatz_tree_stats(
    backbone_length: int,
    branch_length: int,
    max_depth: int,
) -> dict:
    """
    Convenience helper: generate the inverse Collatz tree and return
    basic graph stats (number of nodes, edges, parity counts, etc.).
    """
    df_edges = generate_collatz_tree(
        backbone_length=backbone_length,
        branch_length=branch_length,
        max_depth=max_depth,
    )
    return compute_basic_graph_stats(df_edges)


def safe_int(x, default: int = 1) -> int:
    """
    Convert a value to int safely.
    This protects the Gradio app from crashing when users type invalid input.
    """
    try:
        return int(x)
    except Exception:
        return default