File size: 1,506 Bytes
8797abf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import numpy as np

def calculate_frustration_score(path_vertices):
    """
    Analyzes the 'winding' of the Sperner Walk to detect topological frustration.
    
    Frustration Score is defined as the ratio of Total Path Length to Net Displacement.
    
    Interpretability:
    - ~1.0: Perfect Alignment. The solver moved directly to the consensus.
    - 1.5 - 3.0: Moderate Complexity. Non-linear trade-offs.
    - > 3.0: High Topological Frustration. Objectives are conflicting or orthogonally opposed.
    
    Args:
        path_vertices (list of array-like): Sequence of points (centroids) visited by the solver.
        
    Returns:
        float: The Frustration Score. Returns 1.0 for short paths (<2 steps).
               Returns 999.0 if net displacement is effectively zero (loop).
    """
    if not path_vertices or len(path_vertices) < 2:
        return 1.0
        
    path = np.array(path_vertices)
    
    # 1. Calculate total distance walked (sum of Euclidean steps)
    diffs = path[1:] - path[:-1]
    distances = np.linalg.norm(diffs, axis=1)
    total_dist = np.sum(distances)
        
    # 2. Calculate displacement (Start to Finish)
    start = path[0]
    end = path[-1]
    displacement = np.linalg.norm(end - start)
    
    # Avoid division by zero
    if displacement < 1e-9: 
        return 999.0 # Loop detected or returned to start
    
    # Ratio: How much did we wander?
    frustration_index = total_dist / displacement
    
    return float(frustration_index)