Analysis Module

Overview

At a Glance

Purpose:

Analyze network topology, link utilization, and spectrum usage patterns

Location:

fusion/analysis/

Key Files:

network_analysis.py

Depends On:

numpy, fusion.utils.logging_config

Used By:

Simulation reporting, performance analysis scripts

The analysis module provides utilities for examining network state during and after simulations. It answers questions like “How congested is the network?”, “Which links are bottlenecks?”, and “What’s the overall spectrum utilization?”

Developers work here when they need to add new analysis metrics, modify how utilization is calculated, or integrate analysis into new reporting features.

Key Concepts

Link Utilization

The ratio of occupied spectrum slots to total available slots on a link. A value of 1.0 means fully utilized, 0.0 means empty.

Bottleneck Link

A link whose utilization exceeds a threshold (default 80%). These links limit network capacity and cause blocking.

Bidirectional Links

Network links exist in both directions (A-B and B-A). Analysis methods handle this by either processing each direction separately or normalizing to count physical links once.

Cores Matrix

The spectrum state for a link, stored as a 2D array with shape (num_cores, num_slots). Values indicate slot status:

  • 0: Free slot

  • positive int: Occupied by lightpath with that ID

  • negative int: Guard band for lightpath with abs(value) ID

Note

This module currently uses the legacy dict format for network_spectrum (v5.5.0 compatibility). It will be migrated to use NetworkState and LinkSpectrum objects directly in v6.1.0.

Architecture

fusion/analysis/
├── __init__.py              # Exports NetworkAnalyzer
├── network_analysis.py      # NetworkAnalyzer class
├── README.md                # Module documentation
└── tests/
    ├── __init__.py
    ├── README.md
    └── test_network_analysis.py

Data Flow

  1. Input: network_spectrum dict from simulation engine (or NetworkState.network_spectrum_dict)

  2. Processing: Iterate over links, analyze cores matrices, aggregate statistics

  3. Output: Dictionary of metrics (utilization stats, bottleneck lists, congestion data)

Components

network_analysis.py

Purpose:

Provides the NetworkAnalyzer class with static analysis methods

Key Classes:

NetworkAnalyzer

The NetworkAnalyzer class contains four static methods for analyzing network state:

get_link_usage_summary()

Returns per-link usage statistics including usage count, throughput, and link number. Processes each directional link separately.

from fusion.analysis import NetworkAnalyzer

# Get usage summary for all links
usage = NetworkAnalyzer.get_link_usage_summary(network_spectrum)
# Returns: {
#     "A-B": {
#         "usage_count": 10,    # Number of allocations on this link
#         "throughput": 100.5,  # Total bandwidth served (Gbps)
#         "link_num": 1         # Link index in topology
#     },
#     ...
# }

analyze_network_congestion()

Calculates network-wide congestion metrics including total occupied slots, guard slots, and active request counts.

# Analyze full network
congestion = NetworkAnalyzer.analyze_network_congestion(network_spectrum)

# Analyze specific paths only
congestion = NetworkAnalyzer.analyze_network_congestion(
    network_spectrum,
    specific_paths=[("A", "B"), ("C", "D")]
)
# Returns: {
#     "total_occupied_slots": 1500,   # Slots with data or guard bands
#     "total_guard_slots": 200,       # Slots used for guard bands only
#     "active_requests": 45,          # Unique lightpath IDs found
#     "links_analyzed": 10,           # Number of links processed
#     "avg_occupied_per_link": 150.0, # Mean occupied slots per link
#     "avg_guard_per_link": 20.0      # Mean guard slots per link
# }

get_network_utilization_stats()

Calculates aggregate utilization statistics across the network.

stats = NetworkAnalyzer.get_network_utilization_stats(network_spectrum)
# Returns: {
#     "overall_utilization": 0.45,      # Ratio of occupied to total slots
#     "average_link_utilization": 0.42, # Mean utilization across all links
#     "max_link_utilization": 0.85,     # Highest link utilization
#     "min_link_utilization": 0.10,     # Lowest link utilization
#     "total_slots": 10240,             # Total spectrum slots in network
#     "occupied_slots": 4608,           # Slots currently in use
#     "links_processed": 32             # Number of physical links analyzed
# }

identify_bottleneck_links()

Finds links exceeding a utilization threshold, sorted by utilization descending.

# Find links above 80% utilization (default)
bottlenecks = NetworkAnalyzer.identify_bottleneck_links(network_spectrum)

# Custom threshold
bottlenecks = NetworkAnalyzer.identify_bottleneck_links(
    network_spectrum,
    threshold=0.9
)
# Returns: [
#     {
#         "link_key": "A-B",      # Normalized link identifier
#         "utilization": 0.95,    # Max core utilization on this link
#         "usage_count": 50,      # Number of allocations
#         "throughput": 500.0     # Total bandwidth served (Gbps)
#     },
#     ...  # Sorted by utilization descending
# ]

Dependencies

This Module Depends On

  • fusion.utils.logging_config - Logging utilities

  • External: numpy - Array operations for spectrum matrix analysis

Modules That Depend On This

  • fusion.reporting - Uses analysis for simulation reports

  • fusion.core.metrics - May use for real-time monitoring

Development Guide

Getting Started

  1. Read the Key Concepts section above

  2. Examine network_analysis.py to understand the NetworkAnalyzer class

  3. Run the tests to see example inputs and expected outputs

Common Tasks

Adding a new analysis metric

  1. Add a new static method to NetworkAnalyzer in network_analysis.py

  2. Follow the existing pattern: accept network_spectrum dict, return a dict

  3. Handle bidirectional links appropriately (count once or separately)

  4. Add comprehensive tests in tests/test_network_analysis.py

  5. Update the module README

Modifying utilization calculation

  1. Locate the relevant method (likely get_network_utilization_stats)

  2. Update the calculation logic

  3. Update tests to reflect new expected values

  4. Document any behavioral changes

Code Patterns

Static Analysis Method Pattern

All analysis methods follow this pattern:

@staticmethod
def analyze_something(network_spectrum: dict) -> dict[str, Any]:
    """
    Analyze network for something.

    :param network_spectrum: Network spectrum database
    :return: Dictionary of analysis results
    """
    # Track processed links to avoid double-counting bidirectional
    processed_links = set()

    for (src, dst), link_data in network_spectrum.items():
        # Normalize key for bidirectional handling
        link_key = f"{min(src, dst)}-{max(src, dst)}"

        if link_key in processed_links:
            continue
        processed_links.add(link_key)

        # Process link_data["cores_matrix"]
        ...

    return {"metric": value, ...}

Testing

Test Location:

fusion/analysis/tests/

Run Tests:

pytest fusion/analysis/tests/ -v

Unit Tests

All NetworkAnalyzer methods have comprehensive unit tests covering:

  • Empty network edge cases

  • Single link scenarios

  • Multiple links with bidirectional handling

  • Missing fields and graceful degradation

  • Parametrized tests for link key formatting

Adding New Tests

Follow the AAA pattern with test classes organized by method:

class TestNewAnalysisMethod:
    """Tests for the new_analysis_method method."""

    def test_empty_network_returns_defaults(self) -> None:
        """Test that empty network returns sensible defaults."""
        # Arrange
        network_spectrum: dict = {}

        # Act
        result = NetworkAnalyzer.new_analysis_method(network_spectrum)

        # Assert
        assert result["metric"] == 0