""" 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