Loss Landscape
NonArchimedeanMachineLearning.ConvexHullTree — Type
ConvexHullTree{S,T,N}A tree structure representing the convex hull of a set of polydiscs.
The convex hull consists of the input polydiscs and all their joins, with edges determined by the containment relation.
Fields
nodes::Vector{ValuationPolydisc{S,T,N}}: All nodes in the tree (input discs + joins)children::Dict{Int,Vector{Int}}: Maps node index to indices of immediate childrenparents::Dict{Int,Vector{Int}}: Maps node index to indices of immediate parentsleaf_indices::Vector{Int}: Indices of the original input discs
NonArchimedeanMachineLearning.build_tree_structure — Method
build_tree_structure(nodes::Vector{ValuationPolydisc{S,T,N}}, num_initial::Int) where {S,T,N}Build parent-child relationships for the convex hull tree.
Arguments
nodes::Vector{ValuationPolydisc{S,T,N}}: All nodes (initial discs first, then joins)num_initial::Int: Number of initial discs (these are the leaves)
Returns
Tuple{Dict{Int,Vector{Int}}, Dict{Int,Vector{Int}}}: (children dict, parents dict)
NonArchimedeanMachineLearning.compute_all_joins — Method
compute_all_joins(initial_discs::Vector{ValuationPolydisc{S,T,N}}) where {S,T,N}Compute all polydiscs in the convex hull by iteratively computing joins.
Starting from the initial list of polydiscs, repeatedly computes pairwise joins until no new polydiscs are generated.
Arguments
initial_discs::Vector{ValuationPolydisc{S,T,N}}: Initial list of polydiscs
Returns
Vector{ValuationPolydisc{S,T,N}}: All polydiscs in the convex hull
NonArchimedeanMachineLearning.compute_subtree_width — Function
compute_subtree_width(tree::ConvexHullTree, node_idx::Int, leaf_width::Float64=1.0)Recursively compute the width needed for a subtree rooted at the given node.
Arguments
tree::ConvexHullTree: The tree structurenode_idx::Int: Index of the root of the subtreeleaf_width::Float64: Width allocated to each leaf node (default: 1.0)
Returns
Float64: Total width needed for the subtree
NonArchimedeanMachineLearning.compute_tree_layout — Method
compute_tree_layout(tree::ConvexHullTree{S,T,N}) where {S,T,N}Compute (x, y) positions for all nodes in the tree for visualization.
Uses a radius-based layout where:
- Y-coordinate is determined by radius (smaller radius = higher position)
- Nodes with the same radius are at the same vertical level
- X-coordinates spread nodes to avoid overlap while respecting tree structure
Arguments
tree::ConvexHullTree{S,T,N}: The convex hull tree
Returns
Tuple{Dict{Int, Tuple{Float64, Float64}}, Dict{Int,Vector{Int}}, Dict{Int,Int}, Int}:
- positions: Maps node index to (x, y) position
- spanning_children: Children in the spanning tree
- spanning_parent: Parent in the spanning tree
- root_idx: Index of the root
NonArchimedeanMachineLearning.convex_hull — Method
convex_hull(discs::Vector{ValuationPolydisc{S,T,N}}) where {S,T,N}Compute the convex hull tree of a list of polydiscs.
The convex hull is a tree whose nodes are the input polydiscs and all their joins, with edges determined by the containment relation.
Arguments
discs::Vector{ValuationPolydisc{S,T,N}}: List of polydiscs
Returns
ConvexHullTree{S,T,N}: The convex hull tree structure
Example
K = PadicField(2, 20)
d1 = ValuationPolydisc([K(0)], [3])
d2 = ValuationPolydisc([K(4)], [3])
d3 = ValuationPolydisc([K(8)], [3])
tree = convex_hull([d1, d2, d3])NonArchimedeanMachineLearning.export_landscape_csv — Method
export_landscape_csv(tree::ConvexHullTree{S,T,N}, landscape::Dict, filename::String) where {S,T,N}Export loss landscape data to CSV format for external plotting.
The CSV format is:
parent_idx,child_idx,geodesic_param,loss_valueArguments
tree::ConvexHullTree{S,T,N}: The convex hull tree structurelandscape::Dict: Loss landscape data from samplelosslandscapefilename::String: Output CSV file path
Example
tree = convex_hull([d1, d2, d3])
landscape = sample_loss_landscape(tree, loss_func, 10)
export_landscape_csv(tree, landscape, "landscape_data.csv")NonArchimedeanMachineLearning.extract_spanning_tree — Method
extract_spanning_tree(tree::ConvexHullTree{S,T,N}) where {S,T,N}Extract a spanning tree from the convex hull DAG.
The convex hull can form a DAG (directed acyclic graph) where nodes have multiple parents. This function extracts a proper tree by:
- Creating a virtual root if there are multiple roots
- Keeping only one parent per node (the one with smallest radius sum, breaking ties by index)
Arguments
tree::ConvexHullTree{S,T,N}: The convex hull tree (potentially a DAG)
Returns
Tuple{Dict{Int,Vector{Int}}, Dict{Int,Int}, Int}: (children, parent, root_idx)
children: Maps node index to list of children in the spanning treeparent: Maps node index to its single parent (-1 for root)root_idx: Index of the root node (or -1 for virtual root)
NonArchimedeanMachineLearning.find_all_roots — Method
find_all_roots(tree::ConvexHullTree)Find all root nodes of the convex hull tree (nodes with no parents).
Returns
Vector{Int}: Indices of all root nodes
NonArchimedeanMachineLearning.find_polydisc_index — Method
find_polydisc_index(discs::Vector{ValuationPolydisc{S,T,N}}, p::ValuationPolydisc{S,T,N}) where {S,T,N}Find the index of a polydisc in a vector using Berkovich equality, or return 0 if not found.
Uses the == operator which checks Berkovich equality: two polydiscs are equal if they have the same radius and their centers differ by elements with valuation >= radius.
Arguments
discs::Vector{ValuationPolydisc{S,T,N}}: Vector of polydiscs to searchp::ValuationPolydisc{S,T,N}: Polydisc to find
Returns
Int: Index of the first equal polydisc in the vector, or 0 if not found
NonArchimedeanMachineLearning.find_root — Method
find_root(tree::ConvexHullTree)Find the root node of the convex hull tree (the node with no parents).
Returns
Int: Index of the root node
NonArchimedeanMachineLearning.geodesic_interpolation — Method
geodesic_interpolation(d1::ValuationPolydisc{S,T,N}, d2::ValuationPolydisc{S,T,N}, x::Real) where {S,T,N}Compute the polydisc at parameter x along the geodesic from d1 to d2.
For two discs with the same center, the geodesic is linear interpolation of radii. If d1 = D(a, r) and d2 = D(a, s) with r ≤ s, then at parameter x ∈ [0,1], the interpolated disc is D(a, (1-x)r + xs).
Note: This function works with actual radii (not valuations) for interpolation. The input discs may have integer valuation radii, but the output will have Float64 radii representing the interpolated actual radius.
Arguments
d1::ValuationPolydisc{S,T,N}: First polydisc (must be contained in d2)d2::ValuationPolydisc{S,T,N}: Second polydisc (must contain d1)x::Real: Interpolation parameter in [0, 1]
Returns
ValuationPolydisc{S,Float64,N}: Interpolated polydisc with Float64 radii
Example
K = PadicField(2, 20)
d1 = ValuationPolydisc([K(0)], [5]) # Small disc, valuation 5
d2 = ValuationPolydisc([K(0)], [2]) # Large disc, valuation 2
d_half = geodesic_interpolation(d1, d2, 0.5) # MidpointNonArchimedeanMachineLearning.is_immediate_parent — Method
is_immediate_parent(parent_idx::Int, child_idx::Int, nodes::Vector{ValuationPolydisc{S,T,N}}) where {S,T,N}Check if parent is an immediate parent of child (no intermediate node).
Returns true if:
- nodes[childidx] ⊆ nodes[parentidx] (containment)
- child has strictly smaller radius than parent (higher valuation = smaller disc)
- There is no intermediate node k with child ⊆ k ⊆ parent
Arguments
parent_idx::Int: Index of potential parentchild_idx::Int: Index of potential childnodes::Vector{ValuationPolydisc{S,T,N}}: All nodes in the tree
Returns
Bool: true if parent is an immediate parent of child
NonArchimedeanMachineLearning.loss_to_color — Function
loss_to_color(loss::Float64, min_loss::Float64, max_loss::Float64, colormap::Symbol=:viridis)Convert a loss value to an RGB color using a colormap.
Arguments
loss::Float64: The loss valuemin_loss::Float64: Minimum loss for normalizationmax_loss::Float64: Maximum loss for normalizationcolormap::Symbol: Color scheme (default: :viridis)
Returns
RGB color from the colormap
NonArchimedeanMachineLearning.plot_loss_landscape — Method
plot_loss_landscape(tree::ConvexHullTree{S,T,N}, landscape::Dict; kwargs...) where {S,T,N}Plot the loss landscape using Plots.jl (if available).
Creates a visualization showing:
- Nodes as points
- Edges colored by loss value
- Loss values along geodesics
Arguments
tree::ConvexHullTree{S,T,N}: The convex hull tree structurelandscape::Dict: Loss landscape data from samplelosslandscape
Keyword Arguments
title::String: Plot title (default: "Loss Landscape")colormap::Symbol: Color scheme (default: :viridis)show_node_labels::Bool: Whether to show node indices (default: true)line_width::Real: Width of edge lines (default: 2)
Returns
Plot object from Plots.jl
Example
using Plots
tree = convex_hull([d1, d2, d3])
landscape = sample_loss_landscape(tree, loss_func, 10)
plt = plot_loss_landscape(tree, landscape, title="My Loss Landscape")
savefig(plt, "landscape.png")Note
Requires Plots.jl to be installed and loaded:
using PlotsNonArchimedeanMachineLearning.plot_tree_simple — Method
plot_tree_simple(tree::ConvexHullTree{S,T,N};
title::String="Convex Hull Tree",
show_node_labels::Bool=true,
line_width::Real=2,
node_size::Real=10,
figsize::Tuple{Int,Int}=(800, 600)) where {S,T,N}Plot the convex hull tree structure without loss coloring.
Useful for visualizing just the tree structure before sampling loss.
Arguments
tree::ConvexHullTree{S,T,N}: The convex hull tree structure
Keyword Arguments
title::String: Plot title (default: "Convex Hull Tree")show_node_labels::Bool: Whether to show node indices (default: true)line_width::Real: Width of edge lines (default: 2)node_size::Real: Size of node markers (default: 10)figsize::Tuple{Int,Int}: Figure size in pixels (default: (800, 600))
Returns
Plot object from Plots.jl
NonArchimedeanMachineLearning.plot_tree_with_loss — Method
plot_tree_with_loss(tree::ConvexHullTree{S,T,N}, landscape::Dict;
title::String="Loss Landscape on Tree",
colormap::Symbol=:viridis,
show_node_labels::Bool=true,
line_width::Real=4,
node_size::Real=8,
figsize::Tuple{Int,Int}=(800, 600)) where {S,T,N}Plot the convex hull tree with edges colored by loss values.
Creates a proper tree visualization where:
- Nodes are positioned in a hierarchical tree layout (root at top)
- Each edge segment is colored according to the loss value at that point
- A colorbar shows the loss scale
Arguments
tree::ConvexHullTree{S,T,N}: The convex hull tree structurelandscape::Dict: Loss landscape data fromsample_loss_landscape
Keyword Arguments
title::String: Plot title (default: "Loss Landscape on Tree")colormap::Symbol: Color scheme (default: :viridis)show_node_labels::Bool: Whether to show node indices (default: true)line_width::Real: Width of edge lines (default: 4)node_size::Real: Size of node markers (default: 8)figsize::Tuple{Int,Int}: Figure size in pixels (default: (800, 600))
Returns
Plot object from Plots.jl
Example
using Plots
tree = NonArchimedeanMachineLearning.convex_hull([d1, d2, d3])
landscape = sample_loss_landscape(tree, loss_func, 20)
plt = plot_tree_with_loss(tree, landscape)
savefig(plt, "tree_landscape.png")NonArchimedeanMachineLearning.print_landscape_summary — Method
print_landscape_summary(tree::ConvexHullTree{S,T,N}, landscape::Dict) where {S,T,N}Print a text-based summary of the loss landscape.
Arguments
tree::ConvexHullTree{S,T,N}: The convex hull tree structurelandscape::Dict: Loss landscape data from samplelosslandscape
Example
tree = convex_hull([d1, d2, d3])
landscape = sample_loss_landscape(tree, loss_func, 10)
print_landscape_summary(tree, landscape)NonArchimedeanMachineLearning.radius_strictly_smaller — Method
radius_strictly_smaller(r1::NTuple{N,T}, r2::NTuple{N,T}) where {N,T}Check if r1 is strictly smaller than r2 in the valuation sense.
A radius is "smaller" if it has higher valuation values (representing a smaller disc). Returns true if all components of r1 >= r2 and at least one is strictly greater.
Arguments
r1::NTuple{N,T}: First radius tuple (valuation)r2::NTuple{N,T}: Second radius tuple (valuation)
Returns
Bool: true if r1 represents a strictly smaller disc than r2
NonArchimedeanMachineLearning.radius_to_valuation — Method
radius_to_valuation(r::Real, p::Integer)Convert an actual radius to a valuation.
For a p-adic disc with actual radius r, the valuation is -log_p(r).
Arguments
r::Real: The actual radiusp::Integer: The prime
Returns
Float64: The valuation (possibly non-integer)
NonArchimedeanMachineLearning.sample_loss_landscape — Method
sample_loss_landscape(tree::ConvexHullTree{S,T,N}, f::Function, num_samples::Int=10) where {S,T,N}Sample function values along geodesics in the convex hull tree.
For each parent-child edge in the tree, this function samples the function f at num_samples points along the geodesic connecting them. The geodesic parameter ranges from 0 (at the child) to 1 (at the parent).
Arguments
tree::ConvexHullTree{S,T,N}: The convex hull tree structuref::Function: Function to evaluate, takes aValuationPolydiscand returns a scalarnum_samples::Int: Number of sample points along each geodesic (default: 10)
Returns
Dict{Tuple{Int,Int}, Vector{Tuple{Float64,Float64}}}: Dictionary mapping (parent_idx, child_idx) pairs to vectors of (x, y) pairs, where:
x ∈ [0,1]is the geodesic parameter (0 = child, 1 = parent)yis the function value at that point
Example
K = PadicField(2, 20)
d1 = ValuationPolydisc([K(0)], [3])
d2 = ValuationPolydisc([K(4)], [3])
tree = convex_hull([d1, d2])
# Define a simple function
f(disc) = sum(disc.radius)
# Sample the landscape
landscape = sample_loss_landscape(tree, f, 5)NonArchimedeanMachineLearning.valuation_to_radius — Method
valuation_to_radius(val::Real, p::Integer)Convert a valuation to an actual radius.
For a p-adic disc with valuation radius val, the actual radius is p^(-val).
Arguments
val::Real: The valuation (can be integer or float)p::Integer: The prime
Returns
Float64: The actual radius as a real number