Download core/cascade_utils.py from s-b3/LifeStack: direct link, hf CLI and curl.
- Browser
- Download file 3.19 kB
-
https://huggingface.co/spaces/s-b3/LifeStack/resolve/main/core/cascade_utils.py
- Command line
-
hf download hf://spaces/s-b3/LifeStack/core/cascade_utils.py
-
curl -L -o cascade_utils.py https://huggingface.co/spaces/s-b3/LifeStack/resolve/main/core/cascade_utils.py
3.19 kB
| import copy | |
| from core.life_state import LifeMetrics, DependencyGraph, CASCADE_DAMPENING_DEFAULT | |
| def animate_cascade(primary_disruption: dict, metrics: LifeMetrics) -> list[dict]: | |
| """Replay the cascade step-by-step and capture intermediate frames. | |
| Returns a list of frames, each: | |
| { 'flat': {metric: value}, 'status': {metric: 'primary'|'first'|'second'|'unchanged'} } | |
| """ | |
| graph = DependencyGraph() | |
| dampening = CASCADE_DAMPENING_DEFAULT | |
| frames = [] | |
| # Frame 0 — initial stable state | |
| base = copy.deepcopy(metrics) | |
| base_flat = base.flatten() | |
| frames.append({'flat': dict(base_flat), 'status': {k: 'unchanged' for k in base_flat}}) | |
| # Frame 1 — primary disruption only (no cascade) | |
| f1 = copy.deepcopy(metrics) | |
| primary_keys = set() | |
| for path, amount in primary_disruption.items(): | |
| if '.' not in path: | |
| continue | |
| primary_keys.add(path) | |
| dom_name, sub_name = path.split('.', 1) | |
| dom = getattr(f1, dom_name, None) | |
| if dom and hasattr(dom, sub_name): | |
| setattr(dom, sub_name, max(0.0, min(100.0, getattr(dom, sub_name) + amount))) | |
| f1_flat = f1.flatten() | |
| frames.append({'flat': dict(f1_flat), | |
| 'status': {k: ('primary' if k in primary_keys else 'unchanged') for k in f1_flat}}) | |
| # Frame 2 — first-order cascade | |
| f2 = copy.deepcopy(f1) | |
| first_order_keys = set() | |
| queue_next = [] | |
| for path, amount in primary_disruption.items(): | |
| if '.' not in path or path not in graph.edges: | |
| continue | |
| for target, weight in graph.edges[path]: | |
| impact = amount * weight * dampening | |
| if abs(impact) >= 0.05: | |
| first_order_keys.add(target) | |
| dom_name, sub_name = target.split('.', 1) | |
| dom = getattr(f2, dom_name, None) | |
| if dom and hasattr(dom, sub_name): | |
| setattr(dom, sub_name, max(0.0, min(100.0, getattr(dom, sub_name) + impact))) | |
| queue_next.append((target, impact)) | |
| f2_flat = f2.flatten() | |
| frames.append({'flat': dict(f2_flat), 'status': { | |
| k: ('primary' if k in primary_keys else 'first' if k in first_order_keys else 'unchanged') | |
| for k in f2_flat | |
| }}) | |
| # Frame 3 — second-order cascade | |
| f3 = copy.deepcopy(f2) | |
| second_order_keys = set() | |
| for src_path, src_mag in queue_next: | |
| if src_path not in graph.edges: | |
| continue | |
| for target, weight in graph.edges[src_path]: | |
| impact = src_mag * weight * dampening | |
| if abs(impact) >= 0.05: | |
| second_order_keys.add(target) | |
| dom_name, sub_name = target.split('.', 1) | |
| dom = getattr(f3, dom_name, None) | |
| if dom and hasattr(dom, sub_name): | |
| setattr(dom, sub_name, max(0.0, min(100.0, getattr(dom, sub_name) + impact))) | |
| f3_flat = f3.flatten() | |
| frames.append({'flat': dict(f3_flat), 'status': { | |
| k: ('primary' if k in primary_keys else 'first' if k in first_order_keys | |
| else 'second' if k in second_order_keys else 'unchanged') | |
| for k in f3_flat | |
| }}) | |
| return frames | |