Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: ci

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
simulation-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Run simulation smoke tests
working-directory: simulation
run: python3 -m unittest discover -s tests -p "test_*.py" -v
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# Node.js / Hardhat
contracts/node_modules/
contracts/node_modules/

# Python
__pycache__/
*.py[cod]
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ The Python prototype in this repository has successfully validated the core hypo

* **Adaptive Routing:** The Cognitive Router successfully learned to **dynamically avoid a congested network link**, using it less than **0.1%** of the time, compared to the Dumb Router which was stuck in congestion nearly **40%** of the time.
* **Performance Gains:** By avoiding these bottlenecks, the Cognitive Router achieved **~22% lower average latency** for successful packet deliveries, proving its ability to optimize for overall network health.
* **Full Analysis:** The complete comparative simulation can be run via the `simulations/run_cognitive_sim.py` script.
* **Known Trade-off:** In the seeded reference run, the Cognitive Router's exploration behaviour delivers only **~24% of packets** (the Dumb Router delivers 100%); the latency figure above is computed over successful deliveries only. These results demonstrate adaptive behaviour, not production readiness — closing the delivery gap is future work (see issue tracker).
* **Full Analysis:** The complete comparative simulation can be run via the `simulations/run_cognitive_sim.py` script; `simulations/run_baseline_sim.py` runs the Dijkstra-only baseline. Smoke tests for both live under `simulation/tests/`.

## Full Project Architecture

Expand Down
Binary file removed simulation/crp/__pycache__/__init__.cpython-310.pyc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Empty file added simulation/tests/__init__.py
Empty file.
73 changes: 73 additions & 0 deletions simulation/tests/test_simulation_smoke.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Smoke tests for the CRP simulation scripts.

These run the shipped entry points end to end with a reduced packet count
and assert the behavioural properties the README advertises, so that future
changes to the routing or network code cannot silently break the prototype's
reference results.
"""
import contextlib
import io
import os
import re
import sys
import unittest

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

from simulations import run_baseline_sim, run_cognitive_sim

PACKETS = 200


def run_sim(module):
"""Run a sim main() with a small packet budget and capture stdout."""
module.NUM_PACKETS = PACKETS
buf = io.StringIO()
with contextlib.redirect_stdout(buf):
module.main()
return buf.getvalue()


class CognitiveSimSmokeTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.output = run_sim(run_cognitive_sim)

def test_simulation_completes(self):
self.assertIn("[SUCCESS] Phase 4: Comparative analysis complete.", self.output)

def test_dumb_router_delivers_all_packets(self):
self.assertIn(f"Success Rate: 100.00% ({PACKETS}/{PACKETS})", self.output)

def test_cognitive_router_avoids_congested_link(self):
# Second "Trips through Congested Link" line is the cognitive router.
trips = re.findall(r"Trips through Congested Link: (\d+)/", self.output)
self.assertEqual(len(trips), 2)
cognitive_trips = int(trips[1])
self.assertLess(
cognitive_trips / PACKETS,
0.05,
"cognitive router should use the congested link in <5% of trips",
)

def test_cognitive_router_reports_latency_gain(self):
match = re.search(r"Performance Improvement \(Lower Latency\): ([\d.]+)%", self.output)
self.assertIsNotNone(match, "expected a latency improvement summary line")
self.assertGreater(float(match.group(1)), 0.0)

def test_cognitive_router_delivers_some_packets(self):
match = re.search(r"COGNITIVE ROUTER \(CRP\) ---\n Success Rate: ([\d.]+)%", self.output)
self.assertIsNotNone(match)
self.assertGreater(float(match.group(1)), 0.0)


class BaselineSimSmokeTest(unittest.TestCase):
def test_baseline_finds_west_to_east_route(self):
output = run_sim(run_baseline_sim)
self.assertIn("GATEWAY_WEST", output)
self.assertIn("GATEWAY_EAST", output)
self.assertIn("[SUCCESS] Phase 2: Baseline 'Dumb' Router executed.", output)


if __name__ == "__main__":
unittest.main()
Loading