Physalum Polycephalum

import proximitygraphs as pg
from proximitygraphs.biologicalgraphs import FungalGraph
import numpy as np
import matplotlib.pyplot as plt

Physalum Polycephalum#

random_state = 0
points = pg.SetPoints.uniform_square(20, seed=random_state)
points.draw(figsize=(8, 8), v_color='blue', v_size=20)
(<Figure size 800x800 with 1 Axes>, <Axes: title={'center': 'SetPoints'}>)
../_images/8d6bb1f0acfb6ae8d1c67be3f2306aec9ca2908bc45010d6653b2ce6de41ad87.png
ph = pg.PhysarumGraph(points, sources=[0], steps=1000, dt=0.05, gamma=1.2, eps=1e-3, base_graph='delaunay')
ph.draw(
    figsize=(7, 7),
    e_size=[3],
    e_color="darkgreen",
    v_size=8
)
(<Figure size 700x700 with 1 Axes>, <Axes: title={'center': 'Physarum Graph'}>)
../_images/b06dd504ea8317cfe9db159bf405fcfda63a5f8d96f8e646694f404f28c565ee.png
fg = FungalGraph(points, sources=[0, 10], steps=1000, dt=0.05, gamma=1.2, eps=1e-3, max_degree=4, prune_weak_factor=0.3)
print(f"Nodos: {fg.n}")
print(f"Aristas: {fg.m}")
print(f"Componentes conexas: {fg.cc}")  # Debe ser 1
fg.draw(
    figsize=(7, 7),
    e_size=[2],
    e_color="brown",
    v_size=10
)
Nodos: 20
Aristas: 30
Componentes conexas: 1
(<Figure size 700x700 with 1 Axes>, <Axes: title={'center': 'Fungal Graph'}>)
../_images/b7c2f765652a4db7fbb4f3024613944fd4f0119321f30dab2a4c30b763a898fe.png
conservative = FungalGraph(
    points,
    max_degree=4,                      # Máximo 4 conexiones por nodo
    distance_threshold_percentile=60,  # Solo aristas cortas
    growth_iterations=50,              # Pocas iteraciones
    prune_weak_factor=0.2,             # Poda ligera
    seed=42
)

print("\nCONSERVADORA:")
print(f"  Aristas: {conservative.m}")
print(f"  Grado medio: {sum(conservative.graph.degree())/conservative.n:.2f}")
print(f"  Grado máximo: {max(conservative.graph.degree())}")

# Configuración BALANCEADA (uso general)
balanced = FungalGraph(
    points,
    max_degree=6,                      # Máximo 6 conexiones por nodo
    distance_threshold_percentile=75,  # Balance de distancias
    growth_iterations=100,             # Iteraciones estándar
    prune_weak_factor=0.3,             # Poda moderada
    seed=42
)

print("\nBALANCEADA:")
print(f"  Aristas: {balanced.m}")
print(f"  Grado medio: {sum(balanced.graph.degree())/balanced.n:.2f}")
print(f"  Grado máximo: {max(balanced.graph.degree())}")

# Configuración ROBUSTA (alta redundancia)
robust = FungalGraph(
    points,
    max_degree=8,                      # Máximo 8 conexiones por nodo
    distance_threshold_percentile=85,  # Considera más aristas
    growth_iterations=150,             # Más iteraciones
    prune_weak_factor=0.1,             # Poda mínima
    seed=42
)

print("\nROBUSTA:")
print(f"  Aristas: {robust.m}")
print(f"  Grado medio: {sum(robust.graph.degree())/robust.n:.2f}")
print(f"  Grado máximo: {max(robust.graph.degree())}")
CONSERVADORA:
  Aristas: 32
  Grado medio: 3.20
  Grado máximo: 4

BALANCEADA:
  Aristas: 42
  Grado medio: 4.20
  Grado máximo: 6

ROBUSTA:
  Aristas: 59
  Grado medio: 5.90
  Grado máximo: 8
conservative.draw(
    figsize=(7, 7),
    e_size=[2],
    e_color="brown",
    v_size=10
)
balanced.draw(
    figsize=(7, 7),
    e_size=[2],
    e_color="orange",
    v_size=10
)
robust.draw(
    figsize=(7, 7),
    e_size=[2],
    e_color="red",
    v_size=10
)
(<Figure size 700x700 with 1 Axes>, <Axes: title={'center': 'Fungal Graph'}>)
../_images/ac400b449d4c56640055f7a508bdaac1bf2045258cc5a034a46cb49395c30b48.png ../_images/90e4baeaf04e23b1bdfa78114328c73add61ad0104520545dfb104fa507ac6c7.png ../_images/045eaa196600b3f1b5960bdb6cc224b5b4a7390078f22fedfa7181ae6fc0d286.png
from proximitygraphs import MST, DelaunayG

mst = MST(points)
delaunay = DelaunayG(points)
fungal = FungalGraph(points, seed=42)

import numpy as np

print(f"\n{'Grafo':<20} {'Aristas':<10} {'Comp.':<8} {'Long. Total':<15} {'Grado Medio':<12}")
print("-"*70)
print(f"{'MST':<20} {mst.m:<10} {mst.cc:<8} {sum(mst.lengths):<15.2f} {np.mean(mst.graph.degree()):<12.2f}")
print(f"{'Delaunay':<20} {delaunay.m:<10} {delaunay.cc:<8} {sum(delaunay.lengths):<15.2f} {np.mean(delaunay.graph.degree()):<12.2f}")
print(f"{'FungalGraph':<20} {fungal.m:<10} {fungal.cc:<8} {sum(fungal.lengths):<15.2f} {np.mean(fungal.graph.degree()):<12.2f}")
Grafo                Aristas    Comp.    Long. Total     Grado Medio 
----------------------------------------------------------------------
MST                  19         1        3.28            1.90        
Delaunay             49         1        14.33           4.90        
FungalGraph          42         1        12.96           4.20        
import matplotlib.pyplot as plt

fig, axes = plt.subplots(2, 2, figsize=(14, 14))

# MST
axes[0, 0].scatter(points.points[:, 0], points.points[:, 1], c='darkblue', s=30, zorder=3)
for i, j in mst.graph.get_edgelist():
    p1, p2 = points.points[i], points.points[j]
    axes[0, 0].plot([p1[0], p2[0]], [p1[1], p2[1]], 'gray', linewidth=1, alpha=0.6)
axes[0, 0].set_title(f'MST\n{mst.m} aristas', fontsize=12, fontweight='bold')
axes[0, 0].axis('equal')
axes[0, 0].axis('off')

# Delaunay
axes[0, 1].scatter(points.points[:, 0], points.points[:, 1], c='darkblue', s=30, zorder=3)
for i, j in delaunay.graph.get_edgelist():
    p1, p2 = points.points[i], points.points[j]
    axes[0, 1].plot([p1[0], p2[0]], [p1[1], p2[1]], 'gray', linewidth=1, alpha=0.6)
axes[0, 1].set_title(f'Delaunay\n{delaunay.m} aristas', fontsize=12, fontweight='bold')
axes[0, 1].axis('equal')
axes[0, 1].axis('off')

# FungalGraph Conservadora
axes[1, 0].scatter(points.points[:, 0], points.points[:, 1], c='darkblue', s=30, zorder=3)
for i, j in conservative.graph.get_edgelist():
    p1, p2 = points.points[i], points.points[j]
    axes[1, 0].plot([p1[0], p2[0]], [p1[1], p2[1]], 'green', linewidth=1.5, alpha=0.6)
axes[1, 0].set_title(f'FungalGraph (Conservadora)\n{conservative.m} aristas', 
                     fontsize=12, fontweight='bold')
axes[1, 0].axis('equal')
axes[1, 0].axis('off')

# FungalGraph Balanceada
axes[1, 1].scatter(points.points[:, 0], points.points[:, 1], c='darkblue', s=30, zorder=3)
for i, j in balanced.graph.get_edgelist():
    p1, p2 = points.points[i], points.points[j]
    axes[1, 1].plot([p1[0], p2[0]], [p1[1], p2[1]], 'orange', linewidth=1.5, alpha=0.6)
axes[1, 1].set_title(f'FungalGraph (Balanceada)\n{balanced.m} aristas', 
                     fontsize=12, fontweight='bold')
axes[1, 1].axis('equal')
axes[1, 1].axis('off')

plt.suptitle('Comparación de Topologías - Clase FungalGraph', 
            fontsize=16, fontweight='bold', y=0.98)
plt.tight_layout()
../_images/41a369a503542d484267cc6d3ccf624b4cea4c43ce846512627fd9955dc97a21.png