Spaces:
Sleeping
Sleeping
File size: 5,584 Bytes
c276e2c | 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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | """
complexity_analysis.py β Environment Complexity Report
=======================================================
Generates a formal mathematical analysis of the environment's
state space, action space, and branching factor.
This is the kind of analysis academic reviewers love to see.
Usage:
python examples/complexity_analysis.py
"""
import sys
import os
import math
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
try:
from server.environment import TASKS, ROUTES, CARRIERS, LogisticsAction
except ImportError:
print("Run from project root: python examples/complexity_analysis.py")
sys.exit(1)
# ββ Colors βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
B = "\033[1m"; D = "\033[2m"; C = "\033[96m"; G = "\033[92m"
Y = "\033[93m"; R = "\033[91m"; M = "\033[95m"; X = "\033[0m"
def factorial(n):
return math.factorial(n) if n >= 0 else 1
def comb(n, k):
return math.comb(n, k)
def analyze_task(task_id: str, task_def: dict):
n_shipments = len(task_def["shipments"])
n_routes = len(ROUTES)
n_carriers = len(CARRIERS)
max_turns = task_def["max_turns"]
n_disruptions = len(task_def["disruptions"])
actions_per_turn = 4 # max sub-step budget
# Action space per step
n_reroute = n_shipments * (n_routes - 1) * n_carriers # shipment Γ route Γ carrier
n_priority = sum(comb(n_shipments, k) for k in range(1, min(4, n_shipments + 1)))
n_communicate = n_shipments # message content is free-text (infinite)
n_escalate = n_shipments
n_status = 1
n_end_turn = 1
# Total discrete actions (excluding free-text)
total_discrete = n_reroute + n_priority + n_communicate + n_escalate + n_status + n_end_turn
# Episode branching factor
branching_per_turn = total_discrete ** actions_per_turn
total_episode_paths = branching_per_turn ** max_turns
# State space (combinatorial)
shipment_states = 4 # IN_TRANSIT, DELAYED, CRITICAL, RESOLVED
state_space = (shipment_states ** n_shipments) * (2 ** n_shipments) # status Γ priority
# Information content
info_bits = math.log2(total_episode_paths) if total_episode_paths > 0 else 0
print(f"\n {B}{C}{'='*55}{X}")
print(f" {B}{task_id}: {task_def['name']}{X}")
print(f" {D}{task_def['description']}{X}")
print(f" {B}{C}{'='*55}{X}")
print(f"\n {M}Scenario Parameters{X}")
print(f" Shipments : {B}{n_shipments}{X}")
print(f" Routes available : {B}{n_routes}{X}")
print(f" Carriers : {B}{n_carriers}{X}")
print(f" Disruptions : {B}{n_disruptions}{X}")
print(f" Max turns : {B}{max_turns}{X}")
print(f" Actions per turn : {B}{actions_per_turn}{X}")
print(f"\n {M}Action Space (per step){X}")
print(f" reroute_shipment : {B}{n_reroute:>6}{X} (ship Γ route Γ carrier)")
print(f" set_priority : {B}{n_priority:>6}{X} (C(n,1)+C(n,2)+C(n,3))")
print(f" communicate_eta : {B}{n_communicate:>6}{X} + β free-text messages")
print(f" escalate : {B}{n_escalate:>6}{X}")
print(f" get_network_status : {B}{n_status:>6}{X}")
print(f" end_turn : {B}{n_end_turn:>6}{X}")
print(f" {B}Total discrete : {G}{total_discrete:>6}{X}")
print(f"\n {M}Episode Complexity{X}")
print(f" Branching/turn : {B}{branching_per_turn:.2e}{X} ({total_discrete}^{actions_per_turn})")
print(f" Total paths : {B}{total_episode_paths:.2e}{X} (branch^{max_turns})")
print(f" Information : {B}{info_bits:.1f} bits{X}")
print(f" State space : {B}{state_space:,}{X} ({shipment_states}^{n_shipments} Γ 2^{n_shipments})")
return {
"task": task_id,
"shipments": n_shipments,
"action_space": total_discrete,
"branching_factor": branching_per_turn,
"total_paths": total_episode_paths,
"info_bits": round(info_bits, 1),
"state_space": state_space,
}
def main():
print(f"\n{B}{'β'*60}{X}")
print(f"{B}π Logistics Shipment RL β Complexity Analysis{X}")
print(f"{B}{'β'*60}{X}")
all_results = []
for task_id, task_def in TASKS.items():
result = analyze_task(task_id, task_def)
all_results.append(result)
# Summary comparison
print(f"\n\n{B}{'β'*60}{X}")
print(f"{B}π Cross-Task Complexity Comparison{X}")
print(f"{'β'*60}")
print(f" {'Task':<14} {'Ships':>5} {'Actions':>8} {'Branch/Turn':>14} {'Total Paths':>16} {'Bits':>6}")
print(f" {'β'*14} {'β'*5} {'β'*8} {'β'*14} {'β'*16} {'β'*6}")
for r in all_results:
color = G if r["total_paths"] < 1e20 else Y if r["total_paths"] < 1e50 else R
print(f" {r['task']:<14} {r['shipments']:>5} {r['action_space']:>8} "
f"{r['branching_factor']:>14.2e} {color}{r['total_paths']:>16.2e}{X} "
f"{r['info_bits']:>6.0f}")
hardest = max(all_results, key=lambda x: x["total_paths"])
print(f"\n {B}Most complex: {R}{hardest['task']}{X}")
print(f" {D}With {hardest['total_paths']:.2e} possible episode trajectories,{X}")
print(f" {D}this environment is non-trivial for brute-force search.{X}")
print(f" {D}Effective exploration requires intelligent credit assignment (GRPO).{X}")
print(f"\n{B}{'β'*60}{X}\n")
if __name__ == "__main__":
main()
|