topolib 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. topolib/__init__.py +4 -0
  2. topolib/analysis/__init__.py +4 -0
  3. topolib/analysis/metrics.py +80 -0
  4. topolib/analysis/traffic_matrix.py +344 -0
  5. topolib/assets/AMRES.json +1265 -0
  6. topolib/assets/Abilene.json +285 -0
  7. topolib/assets/Bell_canada.json +925 -0
  8. topolib/assets/Brazil.json +699 -0
  9. topolib/assets/CESNET.json +657 -0
  10. topolib/assets/CORONET.json +1957 -0
  11. topolib/assets/China.json +1135 -0
  12. topolib/assets/DT-14.json +470 -0
  13. topolib/assets/DT-17.json +525 -0
  14. topolib/assets/DT-50.json +1515 -0
  15. topolib/assets/ES-30.json +967 -0
  16. topolib/assets/EURO-16.json +455 -0
  17. topolib/assets/FR-43.json +1277 -0
  18. topolib/assets/FUNET.json +317 -0
  19. topolib/assets/GCN-BG.json +855 -0
  20. topolib/assets/GRNET.json +1717 -0
  21. topolib/assets/HyperOne.json +255 -0
  22. topolib/assets/IT-21.json +649 -0
  23. topolib/assets/India.json +517 -0
  24. topolib/assets/JPN-12.json +331 -0
  25. topolib/assets/KOREN.json +287 -0
  26. topolib/assets/NORDUNet.json +783 -0
  27. topolib/assets/NSFNet.json +399 -0
  28. topolib/assets/PANEURO.json +757 -0
  29. topolib/assets/PAVLOV.json +465 -0
  30. topolib/assets/PLN-12.json +343 -0
  31. topolib/assets/SANReN.json +161 -0
  32. topolib/assets/SERBIA-MONTENEGRO.json +139 -0
  33. topolib/assets/Telefonica-21.json +637 -0
  34. topolib/assets/Turk_Telekom.json +551 -0
  35. topolib/assets/UKNet.json +685 -0
  36. topolib/assets/Vega_Telecom.json +819 -0
  37. topolib/elements/__init__.py +5 -0
  38. topolib/elements/link.py +121 -0
  39. topolib/elements/node.py +230 -0
  40. topolib/topology/__init__.py +4 -0
  41. topolib/topology/path.py +84 -0
  42. topolib/topology/topology.py +469 -0
  43. topolib/visualization/__init__.py +1 -0
  44. topolib/visualization/_qt_screenshot.py +103 -0
  45. topolib/visualization/_qt_window.py +78 -0
  46. topolib/visualization/_templates.py +101 -0
  47. topolib/visualization/mapview.py +316 -0
  48. topolib-0.8.0.dist-info/METADATA +148 -0
  49. topolib-0.8.0.dist-info/RECORD +51 -0
  50. topolib-0.8.0.dist-info/WHEEL +4 -0
  51. topolib-0.8.0.dist-info/licenses/LICENSE +22 -0
@@ -0,0 +1,101 @@
1
+ """
2
+ HTML templates for MapView visualization.
3
+
4
+ This module contains HTML/CSS templates used to render topology maps.
5
+ """
6
+
7
+ # Template for the topology title overlay
8
+ TITLE_TEMPLATE = """
9
+ <div style="position: fixed;
10
+ top: 10px; left: 50px; width: 300px; height: 50px;
11
+ background-color: white; border:2px solid grey; z-index:9999;
12
+ font-size:16px; font-weight: bold; padding: 10px">
13
+ {title}
14
+ </div>
15
+ """
16
+
17
+ # Template for node popup information
18
+ NODE_POPUP_TEMPLATE = """
19
+ <div style="width: 200px">
20
+ <h4>{name}</h4>
21
+ <b>ID:</b> {id}<br>
22
+ <b>Latitude:</b> {latitude:.6f}<br>
23
+ <b>Longitude:</b> {longitude:.6f}<br>
24
+ {optional_attributes}
25
+ </div>
26
+ """
27
+
28
+ # Template for link popup information
29
+ LINK_POPUP_TEMPLATE = """
30
+ <b>Link {id}</b><br>
31
+ From: {source_name} (ID: {source_id})<br>
32
+ To: {target_name} (ID: {target_id})<br>
33
+ Length: {length:.2f} km
34
+ """
35
+
36
+ # Node marker style configuration
37
+ NODE_MARKER_CONFIG = {
38
+ 'radius': 8,
39
+ 'color': 'blue',
40
+ 'fill': True,
41
+ 'fillColor': 'blue',
42
+ 'fillOpacity': 0.7
43
+ }
44
+
45
+ # Link line style configuration
46
+ LINK_LINE_CONFIG = {
47
+ 'color': 'gray',
48
+ 'weight': 2,
49
+ 'opacity': 0.7
50
+ }
51
+
52
+ # Map default configuration
53
+ MAP_DEFAULT_CONFIG = {
54
+ 'zoom_start': 5,
55
+ 'tiles': 'OpenStreetMap',
56
+ 'control_scale': True
57
+ }
58
+
59
+
60
+ def format_node_popup(node) -> str:
61
+ """Format a node's information for popup display.
62
+
63
+ :param node: Node object to format.
64
+ :return: Formatted HTML string.
65
+ :rtype: str
66
+ """
67
+ optional_attrs = []
68
+
69
+ if hasattr(node, 'weight') and node.weight:
70
+ optional_attrs.append(f"<b>Weight:</b> {node.weight}<br>")
71
+ if hasattr(node, 'pop') and node.pop:
72
+ optional_attrs.append(f"<b>Population:</b> {node.pop:,}<br>")
73
+ if hasattr(node, 'dc') and node.dc:
74
+ optional_attrs.append(f"<b>DC:</b> {node.dc}<br>")
75
+ if hasattr(node, 'ixp') and node.ixp:
76
+ optional_attrs.append(f"<b>IXP:</b> {node.ixp}<br>")
77
+
78
+ return NODE_POPUP_TEMPLATE.format(
79
+ name=node.name,
80
+ id=node.id,
81
+ latitude=node.latitude,
82
+ longitude=node.longitude,
83
+ optional_attributes=''.join(optional_attrs)
84
+ )
85
+
86
+
87
+ def format_link_popup(link) -> str:
88
+ """Format a link's information for popup display.
89
+
90
+ :param link: Link object to format.
91
+ :return: Formatted HTML string.
92
+ :rtype: str
93
+ """
94
+ return LINK_POPUP_TEMPLATE.format(
95
+ id=link.id,
96
+ source_name=link.source.name,
97
+ source_id=link.source.id,
98
+ target_name=link.target.name,
99
+ target_id=link.target.id,
100
+ length=link.length
101
+ )
@@ -0,0 +1,316 @@
1
+ """
2
+ MapView class for visualizing network topologies.
3
+
4
+ This module provides visualization methods for Topology objects using Folium.
5
+ """
6
+
7
+ from typing import Optional
8
+ import webbrowser
9
+ import tempfile
10
+ import os
11
+ import sys
12
+ import re
13
+ import urllib.request
14
+ import hashlib
15
+ import subprocess
16
+ from pathlib import Path
17
+ from topolib.topology import Topology
18
+ import folium
19
+ from folium import plugins
20
+ from topolib.elements.link import Link
21
+ from topolib.elements.node import Node
22
+ from . import _templates
23
+
24
+ # Global cache directory for downloaded resources
25
+ CACHE_DIR = Path.home() / '.topolib' / 'cache'
26
+ CACHE_DIR.mkdir(parents=True, exist_ok=True)
27
+
28
+
29
+ class MapView:
30
+ """
31
+ Provides interactive visualization methods for Topology objects using Folium.
32
+
33
+ This class creates interactive HTML maps with OpenStreetMap tiles,
34
+ displaying network nodes as clickable markers and links as lines between them.
35
+ """
36
+
37
+ def __init__(self, topology: Topology) -> None:
38
+ """Create a MapView instance for a Topology.
39
+
40
+ :param topology: Topology object to visualize.
41
+ :type topology: topolib.topology.Topology
42
+ """
43
+ self.topology = topology
44
+ self._map = None
45
+
46
+ def _create_map(self, include_controls: bool = True) -> folium.Map:
47
+ """Create a Folium map with the current topology.
48
+
49
+ :param include_controls: Whether to include interactive controls (zoom, fullscreen, etc.).
50
+ :type include_controls: bool
51
+ :return: Folium Map object with nodes and links rendered.
52
+ :rtype: folium.Map
53
+ """
54
+ # Get topology name
55
+ topo_name = getattr(self.topology, "name", None) or "Topology"
56
+
57
+ # Calculate map center
58
+ if self.topology.nodes:
59
+ avg_lat = sum(node.latitude for node in self.topology.nodes) / len(
60
+ self.topology.nodes
61
+ )
62
+ avg_lon = sum(node.longitude for node in self.topology.nodes) / len(
63
+ self.topology.nodes
64
+ )
65
+ else:
66
+ avg_lat, avg_lon = 0, 0
67
+
68
+ # Create base map using template configuration
69
+ map_config = _templates.MAP_DEFAULT_CONFIG.copy()
70
+ if not include_controls:
71
+ map_config['zoom_control'] = False
72
+ map_config['control_scale'] = False
73
+
74
+ m = folium.Map(
75
+ location=[avg_lat, avg_lon],
76
+ **map_config
77
+ )
78
+
79
+ # Disable attribution if no controls
80
+ if not include_controls:
81
+ m.get_root().html.add_child(folium.Element("""
82
+ <style>
83
+ .leaflet-control-attribution {
84
+ display: none !important;
85
+ }
86
+ .leaflet-control-zoom {
87
+ display: none !important;
88
+ }
89
+ .leaflet-bar {
90
+ display: none !important;
91
+ }
92
+ </style>
93
+ """))
94
+
95
+ # Add title using template
96
+ title_html = _templates.TITLE_TEMPLATE.format(title=topo_name)
97
+ m.get_root().html.add_child(folium.Element(title_html))
98
+
99
+ # Draw links first (so they appear below nodes)
100
+ for link in self.topology.links:
101
+ coords = [
102
+ [link.source.latitude, link.source.longitude],
103
+ [link.target.latitude, link.target.longitude],
104
+ ]
105
+
106
+ popup_text = _templates.format_link_popup(link)
107
+
108
+ folium.PolyLine(
109
+ coords,
110
+ popup=folium.Popup(popup_text, max_width=300) if include_controls else None,
111
+ **_templates.LINK_LINE_CONFIG
112
+ ).add_to(m)
113
+
114
+ # Draw nodes
115
+ for node in self.topology.nodes:
116
+ popup_html = _templates.format_node_popup(node)
117
+
118
+ folium.CircleMarker(
119
+ location=[node.latitude, node.longitude],
120
+ popup=folium.Popup(popup_html, max_width=300) if include_controls else None,
121
+ tooltip=node.name if include_controls else None,
122
+ **_templates.NODE_MARKER_CONFIG
123
+ ).add_to(m)
124
+
125
+ # Add interactive controls only if requested
126
+ if include_controls:
127
+ # Add fullscreen button
128
+ plugins.Fullscreen().add_to(m)
129
+
130
+ # Add measure control for distance measurement
131
+ plugins.MeasureControl(position='topleft').add_to(m)
132
+
133
+ self._map = m
134
+ return m
135
+
136
+ def show_map(self, mode: str = "window") -> None:
137
+ """Display the interactive map in a web browser or GUI window.
138
+
139
+ Creates an HTML map and displays it either in the system's default web browser
140
+ or in an interactive PyQt window.
141
+
142
+ The map includes:
143
+ - Interactive nodes with clickable popups showing node information
144
+ - Links between nodes with hover tooltips
145
+ - Zoom and pan controls
146
+ - Fullscreen mode
147
+ - Distance measurement tool
148
+
149
+ :param mode: Display mode - "window" opens in PyQt window, "browser" opens in web browser (default: "window").
150
+ :type mode: str
151
+ :raises ImportError: If mode="window" and PyQt6 is not installed.
152
+ :returns: None
153
+ """
154
+ # Suppress Qt warnings early
155
+ if mode == "window":
156
+ os.environ['QT_LOGGING_RULES'] = '*.debug=false;qt.webenginecontext.debug=false;qt.qpa.windows=false'
157
+ os.environ['QTWEBENGINE_CHROMIUM_FLAGS'] = '--disable-logging --log-level=3'
158
+
159
+ m = self._create_map()
160
+
161
+ # Save to temporary HTML file
162
+ with tempfile.NamedTemporaryFile(
163
+ mode="w", suffix=".html", delete=False, encoding='utf-8'
164
+ ) as tmp:
165
+ tmp_path = tmp.name
166
+ m.save(tmp_path)
167
+
168
+ # For window mode, embed external resources
169
+ if mode == "window":
170
+ self._embed_resources(tmp_path)
171
+ self._show_in_window(tmp_path)
172
+ else:
173
+ # Try to open in default web browser
174
+ try:
175
+ webbrowser.open("file://" + os.path.abspath(tmp_path))
176
+ print(
177
+ f"Map opened in browser. If it didn't open, access: file://{os.path.abspath(tmp_path)}")
178
+ except Exception as e:
179
+ print(f"Could not open browser: {e}")
180
+ print(f"You can manually open: {tmp_path}")
181
+
182
+ def _embed_resources(self, html_path: str) -> None:
183
+ """Embed external CSS and JS resources directly into the HTML file.
184
+
185
+ :param html_path: Path to the HTML file to modify.
186
+ :type html_path: str
187
+ """
188
+ with open(html_path, 'r', encoding='utf-8') as f:
189
+ html_content = f.read()
190
+
191
+ # Find all external script and link tags
192
+ script_pattern = r'<script src="(https?://[^"]+)"><\/script>'
193
+ link_pattern = r'<link rel="stylesheet" href="(https?://[^"]+)"[^>]*/?>'
194
+
195
+ # Download and embed scripts with caching
196
+ def replace_script(match):
197
+ url = match.group(1)
198
+ try:
199
+ content = self._get_cached_resource(url)
200
+ return f'<script>{content}</script>'
201
+ except Exception as e:
202
+ print(f"Warning: Could not download {url}: {e}")
203
+ return match.group(0) # Keep original if download fails
204
+
205
+ # Download and embed stylesheets with caching
206
+ def replace_link(match):
207
+ url = match.group(1)
208
+ try:
209
+ content = self._get_cached_resource(url)
210
+ return f'<style>{content}</style>'
211
+ except Exception as e:
212
+ print(f"Warning: Could not download {url}: {e}")
213
+ return match.group(0) # Keep original if download fails
214
+
215
+ html_content = re.sub(script_pattern, replace_script, html_content)
216
+ html_content = re.sub(link_pattern, replace_link, html_content)
217
+
218
+ with open(html_path, 'w', encoding='utf-8') as f:
219
+ f.write(html_content)
220
+
221
+ def _get_cached_resource(self, url: str) -> str:
222
+ """Get resource from cache or download if not cached.
223
+
224
+ :param url: URL of the resource to download.
225
+ :type url: str
226
+ :return: Content of the resource.
227
+ :rtype: str
228
+ """
229
+ # Create a hash of the URL to use as filename
230
+ url_hash = hashlib.md5(url.encode()).hexdigest()
231
+ cache_file = CACHE_DIR / url_hash
232
+
233
+ # Check if cached
234
+ if cache_file.exists():
235
+ with open(cache_file, 'r', encoding='utf-8') as f:
236
+ return f.read()
237
+
238
+ # Download and cache
239
+ print(f"Downloading: {url}")
240
+ with urllib.request.urlopen(url, timeout=10) as response:
241
+ content = response.read().decode('utf-8')
242
+
243
+ # Save to cache
244
+ with open(cache_file, 'w', encoding='utf-8') as f:
245
+ f.write(content)
246
+
247
+ return content
248
+
249
+ def _show_in_window(self, html_path: str) -> None:
250
+ """Display the map in a PyQt window.
251
+
252
+ :param html_path: Path to the HTML file to display.
253
+ :type html_path: str
254
+ :raises ImportError: If PyQt6 is not installed.
255
+ """
256
+ # Get the path to the Qt window script
257
+ qt_script = Path(__file__).parent / '_qt_window.py'
258
+
259
+ # Run the Qt window in a subprocess for isolation
260
+ window_title = self.topology.name or 'Topology Map'
261
+ subprocess.run([sys.executable, str(qt_script), html_path, window_title], check=True)
262
+
263
+ def export_html(self, filename: str) -> None:
264
+ """Export the map as a standalone HTML file.
265
+
266
+ :param filename: Output HTML file path.
267
+ :type filename: str
268
+ """
269
+ m = self._create_map()
270
+ m.save(filename)
271
+
272
+ def export_map_png(self, filename: str, width: int = 1920, height: int = 1080, wait_time: float = 1.0) -> None:
273
+ """Export the map as a PNG image using PyQt6.
274
+
275
+ :param filename: Output PNG file path.
276
+ :type filename: str
277
+ :param width: Width of the exported image in pixels (default: 1920).
278
+ :type width: int
279
+ :param height: Height of the exported image in pixels (default: 1080).
280
+ :type height: int
281
+ :param wait_time: Time in seconds to wait for map rendering before capture (default: 1.0).
282
+ :type wait_time: float
283
+ :raises ImportError: If PyQt6 is not installed.
284
+ """
285
+ # Create map without interactive controls for clean export
286
+ m = self._create_map(include_controls=False)
287
+
288
+ # Save to temporary HTML file
289
+ with tempfile.NamedTemporaryFile(
290
+ mode="w", suffix=".html", delete=False, encoding='utf-8'
291
+ ) as tmp:
292
+ tmp_path = tmp.name
293
+ m.save(tmp_path)
294
+
295
+ # Embed resources for offline rendering
296
+ self._embed_resources(tmp_path)
297
+
298
+ # Get the path to the screenshot script
299
+ screenshot_script = Path(__file__).parent / '_qt_screenshot.py'
300
+
301
+ # Run the screenshot script in a subprocess
302
+ try:
303
+ subprocess.run(
304
+ [sys.executable, str(screenshot_script), tmp_path, filename, str(width), str(height), str(wait_time)],
305
+ check=True,
306
+ capture_output=True,
307
+ text=True
308
+ )
309
+ except subprocess.CalledProcessError as e:
310
+ raise RuntimeError(f"Failed to capture screenshot: {e.stderr}")
311
+ finally:
312
+ # Clean up temp file
313
+ try:
314
+ os.unlink(tmp_path)
315
+ except:
316
+ pass
@@ -0,0 +1,148 @@
1
+ Metadata-Version: 2.4
2
+ Name: topolib
3
+ Version: 0.8.0
4
+ Summary: A compact Python library for modeling, analyzing, and visualizing optical network topologies.
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Keywords: network,topology,optical,analysis,visualization
8
+ Author: Danilo Bórquez-Paredes
9
+ Author-email: danilo.borquez.p@uai.cl
10
+ Requires-Python: >=3.10
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Dist: PyQt6 (>=6.0)
23
+ Requires-Dist: PyQt6-WebEngine (>=6.0)
24
+ Requires-Dist: folium (>=0.14.0)
25
+ Requires-Dist: jsonschema (>=4.0)
26
+ Requires-Dist: networkx (>=2.6)
27
+ Requires-Dist: numpy (>=1.21)
28
+ Project-URL: Documentation, https://topolib.readthedocs.io/
29
+ Project-URL: Homepage, https://gitlab.com/DaniloBorquez/topolib
30
+ Project-URL: Repository, https://gitlab.com/DaniloBorquez/topolib
31
+ Description-Content-Type: text/markdown
32
+
33
+ # Topolib 🚀
34
+
35
+ [![Python Version](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/)
36
+ [![License](https://img.shields.io/badge/license-MIT-lightgrey.svg)](LICENSE)
37
+ [![Issues](https://img.shields.io/badge/issues-on%20GitLab-blue.svg)](https://gitlab.com/DaniloBorquez/topolib/-/issues)
38
+ [![Develop coverage](https://gitlab.com/DaniloBorquez/topolib/badges/develop/coverage.svg)](https://gitlab.com/DaniloBorquez/topolib/-/pipelines?ref=develop)
39
+ [![Release coverage](https://gitlab.com/DaniloBorquez/topolib/badges/release/coverage.svg)](https://gitlab.com/DaniloBorquez/topolib/-/pipelines?ref=release)
40
+ [![Documentation Status](https://readthedocs.org/projects/topolib/badge/?version=latest)](https://topolib.readthedocs.io/en/latest/?badge=latest)
41
+
42
+ > **Topolib** is a compact, modular Python library for modeling, analyzing, and visualizing optical network topologies.
43
+ > **Goal:** Provide researchers and engineers with a simple, extensible toolkit for working with nodes, links, metrics, and map-based visualizations.
44
+ >
45
+ > 🌐 **Model** | 📊 **Analyze** | 🗺️ **Visualize** | 🧩 **Extend**
46
+
47
+ ---
48
+
49
+ ## 📂 Examples
50
+
51
+
52
+ Explore ready-to-run usage examples in the [`examples/`](examples/) folder!
53
+
54
+ - [Show topology on a map](examples/show_topology_in_map.py) 🗺️
55
+ - [Show default topology in map](examples/show_default_topology_in_map.py) 🗺️
56
+ - [Export topology as PNG](examples/export_topology_png.py) 🖼️
57
+ - [Export topology to CSV and JSON](examples/export_csv_json.py) 📄
58
+ - [Export topology and k-shortest paths for FlexNetSim](examples/export_flexnetsim.py) 🔀
59
+ - [Generate traffic demand matrices](examples/traffic_matrices.py) 📊
60
+
61
+ ---
62
+
63
+ ## 🧭 Overview
64
+
65
+ Topolib is organized into four main modules:
66
+
67
+ - 🧱 **Elements:** `Node`, `Link` — basic building blocks
68
+ - 🕸️ **Topology:** `Topology`, `Path` — manage nodes, links, paths, and adjacency
69
+ - 📈 **Analysis:** `Metrics`, `TrafficMatrix` — compute node degree, link stats, connection matrices, and traffic demand matrices
70
+ - 🖼️ **Visualization:** `MapView` — interactive maps with Folium and PyQt6, clean PNG exports
71
+
72
+ ---
73
+
74
+ ## ✨ Features
75
+
76
+ - Modular, extensible design
77
+ - Easy-to-use classes for nodes, links, and paths
78
+ - Built-in metrics and analysis helpers
79
+ - Traffic demand matrix generation with three models (gravitational, DC/IXP, distribution probability)
80
+ - Returns NumPy arrays for efficient mathematical operations
81
+ - Interactive map visualization with Folium and PyQt6
82
+ - Clean PNG export without external dependencies (no Selenium required)
83
+ - Resource caching for faster map rendering
84
+ - JSON import/export and interoperability
85
+ - Ready for Sphinx, Read the Docs, and PyPI
86
+
87
+ ---
88
+
89
+ ## ⚡ Quickstart
90
+
91
+ ```bash
92
+ python -m venv .venv
93
+ source .venv/bin/activate
94
+ pip install -U pip
95
+ pip install topolib
96
+ ```
97
+
98
+ ---
99
+
100
+ ## 📚 Documentation
101
+
102
+ Full documentation: [https://topolib.readthedocs.io/](https://topolib.readthedocs.io/)
103
+
104
+ ---
105
+
106
+ ## 📝 Basic usage
107
+
108
+ ### Creating a topology
109
+
110
+ ```python
111
+ from topolib.elements.node import Node
112
+ from topolib.topology.topology import Topology
113
+
114
+ n1 = Node(1, 'A', 10.0, 20.0)
115
+ n2 = Node(2, 'B', 11.0, 21.0)
116
+ topo = Topology(nodes=[n1, n2])
117
+ # Add links, compute metrics, visualize, etc.
118
+ ```
119
+
120
+ ### Generating traffic matrices
121
+
122
+ ```python
123
+ from topolib.topology import Topology
124
+ from topolib.analysis import TrafficMatrix
125
+
126
+ # Load a topology
127
+ topo = Topology.load_default_topology("DT-14")
128
+
129
+ # Generate traffic matrix using gravitational model
130
+ matrix = TrafficMatrix.gravitational(topo, rate=0.015)
131
+ # Returns NumPy array: matrix[i, j] = traffic from node i to j (Gbps)
132
+
133
+ # Export to CSV
134
+ TrafficMatrix.to_csv(matrix, topo, "traffic_matrix.csv")
135
+ ```
136
+
137
+ ---
138
+
139
+ ## 🛠️ Development
140
+
141
+ See [`CONTRIBUTING.md`](CONTRIBUTING.md) for development guidelines, commit message rules, and pre-commit setup.
142
+
143
+ ---
144
+
145
+ ## 📄 License
146
+
147
+ MIT — see [`LICENSE`](LICENSE) for details.
148
+
@@ -0,0 +1,51 @@
1
+ topolib/__init__.py,sha256=iLmy2rOkHS_4KZWMD8BgT7R3tLMKeaTCDVf3B4FyYxM,91
2
+ topolib/analysis/__init__.py,sha256=946BTvvd_xP47YGgQBlUoC1L0naX-iGycMhsp-hXGzE,111
3
+ topolib/analysis/metrics.py,sha256=2o5PlMVzepDWwSQjzamtKemggqkxh9JuzzCUaeahfok,2555
4
+ topolib/analysis/traffic_matrix.py,sha256=E3PGja6z7t1254AxYCkvUIMFltrQFDBTVeYuMMPKHDQ,10670
5
+ topolib/assets/AMRES.json,sha256=PWQLEOOIpQzDelkWg27EUTg331Ewlqm-jIQGMNyIIdo,27082
6
+ topolib/assets/Abilene.json,sha256=5cnPMbjsNDjmpySdQDYQ2yd83zOFvCRjlAnbX1wyzgk,6010
7
+ topolib/assets/Bell_canada.json,sha256=pjsZBZcp6j-IP57P8MOlcBqnfnLkzbintKzgJxcC7ZE,19921
8
+ topolib/assets/Brazil.json,sha256=_4rSY46CKBd6ylpLLigaUuWjLrP83OYiYorg4wChmFU,14876
9
+ topolib/assets/CESNET.json,sha256=i6ebe-cDZJtTCDbbeuBo-dQwb7dhD4SRdc0I0N0Eczo,13739
10
+ topolib/assets/CORONET.json,sha256=dSpBSR-vBdxeG1IPcnjw5YYwpzujKMceBuLghGt3xQQ,42017
11
+ topolib/assets/China.json,sha256=L3co98t0MYzPApUi0Hv9i-QthDPHZQSsGcCvunspsGA,23820
12
+ topolib/assets/DT-14.json,sha256=IyNZIWelc2lW1eOa6nHOH4HRfCIOGZtBdwFUQhiS5is,9924
13
+ topolib/assets/DT-17.json,sha256=LBqGD3e3ad9nSaFlnJnrIWMk1eEVC6uF6zDElFzPUu8,10972
14
+ topolib/assets/DT-50.json,sha256=4Pe6R3eWaiHB_KOWO2Pprm3veHl6ttZA2dPyh_GxEGQ,31869
15
+ topolib/assets/ES-30.json,sha256=gXrrOGNveIlWNvO214FHcGo08pCCs1mElCRHXdvIJGY,20186
16
+ topolib/assets/EURO-16.json,sha256=LEd_oq9nY9XP-5wzrCcmhe3VI0D_iDlaNg1lAjeRHik,9513
17
+ topolib/assets/FR-43.json,sha256=QK4-95ETMw4C98jMzpgkpL8y2vlSkbiS7mN9-9QCEPw,26797
18
+ topolib/assets/FUNET.json,sha256=RtVbWVmJHGO-a8gSqCiGWkuxjfou-Ep1JWV4b9M2qIc,6650
19
+ topolib/assets/GCN-BG.json,sha256=e24fO_IlVUu6x9S2zpSJWBD7S9Obkw39TkHcKGzayDQ,18299
20
+ topolib/assets/GRNET.json,sha256=xJMwR4DGANRBcLdjv_8gWQp3ymuSSCR2Cws9_sAx9eg,36781
21
+ topolib/assets/HyperOne.json,sha256=jP-BT5jmozezD0AgOkwdb6nXyqiiL6TMy6BjjVOKEGE,5264
22
+ topolib/assets/IT-21.json,sha256=GmYsmC8jycG1WYGwRvVJtnrurZQ7uy8LN0Kmb8Zmg6w,13503
23
+ topolib/assets/India.json,sha256=7wiXKgWBIO0THTpV8pNE8TCriV-zfytI2lPKK6Y3Zoc,10839
24
+ topolib/assets/JPN-12.json,sha256=qz4uZAjE4GvLQnlBpKAiC9Zrp197r5hI8029hsRlDEY,6902
25
+ topolib/assets/KOREN.json,sha256=lKW2if-IdGxQsiX6vpysXpYw__3_6OTWeZ9-oD-h5Eg,5951
26
+ topolib/assets/NORDUNet.json,sha256=X934bx4bTyn98ASz8Eb0-UuEBxnR-3vTy14-gFn8Oms,16412
27
+ topolib/assets/NSFNet.json,sha256=LeU7h6H76HXEyIpUhlzuR6cbs6Q61eEgxmyUMaNUeEk,8375
28
+ topolib/assets/PANEURO.json,sha256=Xh_pmTBOwlusDhAUGpPzJz4tSRXbK-FTsN3Dnlbwf48,15969
29
+ topolib/assets/PAVLOV.json,sha256=YRDqlodGj-zqErX1cwk4bX-XuUkgP1CpiOmtlLIBmIk,9816
30
+ topolib/assets/PLN-12.json,sha256=oxKs0MTe-pEqD-kTa_LATWfDRswwAnlEFubeQlXMFRU,7135
31
+ topolib/assets/SANReN.json,sha256=VUe7JFbzmte6ED3lNyfm1cWhefsapeZ4P-zIG6-rZXc,3394
32
+ topolib/assets/SERBIA-MONTENEGRO.json,sha256=83Mk5yNju7B50JolE1uCwy8wQJgsaBzZ71xxhMGYOSc,2897
33
+ topolib/assets/Telefonica-21.json,sha256=Wom5SQn3lLL-z-ESZ3Du_Fz_ZQ2bzP2_bNhzmnmmW_I,13302
34
+ topolib/assets/Turk_Telekom.json,sha256=5yO0cgtJOmh6ulCCIb8g_nDFSmv8Wn52Yt_Oyoc1Y0w,11533
35
+ topolib/assets/UKNet.json,sha256=9BEkRM9YFeMMpih5kyDY34TsOGFzt5KBGsmgWd6KoB0,14210
36
+ topolib/assets/Vega_Telecom.json,sha256=E07ZCvG4exRj1a5DV8lqS3Sdo5tRm_Lc07IzIjP2EW0,17324
37
+ topolib/elements/__init__.py,sha256=RIQGFgI3_R7Saf679LaP8o8D8kVtM-JadZt6XufJcQ4,75
38
+ topolib/elements/link.py,sha256=2YDEkKdCt91Nv8oiv6gfyECWoeYQaShyhi5DGRvKN2o,3376
39
+ topolib/elements/node.py,sha256=ytxxYvIV9kcsnEV8R0IEFpaXT3-cL5g-djcSkcesBOI,5374
40
+ topolib/topology/__init__.py,sha256=2VRhVm4ZvKBiTDB2T8BDmLZBpwGCVFRF3fvtxxC_d28,86
41
+ topolib/topology/path.py,sha256=oUNwmpBcS6LMMAJIxokROm3MVqr7vRR44M3Fh5ADq_w,2057
42
+ topolib/topology/topology.py,sha256=scAP8ik2rHlpmvcB1CbeHwbVKKUAcPbTNm7oSEvTEOo,16520
43
+ topolib/visualization/__init__.py,sha256=wv065-KB5uDbTaQIASPVfMMW5sE76Bs-q0oai48vAzk,29
44
+ topolib/visualization/_qt_screenshot.py,sha256=npLr_FWYdZq3HVN8_uBsPnPREi6cnbDjU1yaC9m4L04,3541
45
+ topolib/visualization/_qt_window.py,sha256=LI1muAAehkjQ_GyDpPGYVr60GF0dTLCbIxqqzBL7XXs,2503
46
+ topolib/visualization/_templates.py,sha256=BkYlTIZjDI1jEIsYnPStmpQXdItwluODGG4_CVVuUes,2599
47
+ topolib/visualization/mapview.py,sha256=Z4EuKNMAXTHE1VEAmXD7IWPVaPRUIt0ZTMJK5kigZNI,11461
48
+ topolib-0.8.0.dist-info/METADATA,sha256=9s4kosTDA_EFPo7EoA303G39sCikjZJVa8yO1ZjSLfw,5257
49
+ topolib-0.8.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
50
+ topolib-0.8.0.dist-info/licenses/LICENSE,sha256=kbnIP0XU6f2ualiTjEawdlU81IGPBbwc-_GF3N-1e9E,1081
51
+ topolib-0.8.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.2.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,22 @@
1
+
2
+ MIT License
3
+
4
+ Copyright (c) 2025 Danilo Bórquez-Paredes
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.