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 valuation radius (smaller actual radius = higher position)
- Nodes with the same valuation 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 actual radii. If d1 = D(a, r) and d2 = D(a, s) with valuation radii r ≥ s, then at parameter x ∈ [0,1] the actual radius is $(1-x)p^{-r} + xp^{-s}$.
ValuationPolydisc.radius is always returned in valuation coordinates. The interpolation is computed in actual-radius coordinates and converted back to Float64 valuation radii before constructing the result.
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 valuation 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