Decentralized causal chain tracing across fragmented edge data — TPHG construction, LaVE expansion, and probabilistic routing for IoT health networks
Project description
CasFly SDK
This tool builds lag-aware causal graphs from timestamped event logs, traces the most probable multi-device precursor chain for a target event using LaVE, routes expansion across devices via a probabilistic lookup table, and exposes the workflow through a Python SDK and FastAPI service:
TPHG(Temporal Probabilistic Health Graph) constructionLaVE(Lag-aware Viterbi Expansion) for most-probable dependency pathsPLT(Probabilistic Lookup Table) for next-node routing- Multi-device orchestration for decentralized causal chain tracing
- Configurable lag-weight function
f(L)(unity, exponential decay, or per-bin mapping) - Bounded fallback expansion when direct predecessor expansion is exhausted
- Confidence audit outputs (weighted confidence, raw confidence, lag-weight product)
Install
From PyPI (recommended):
# Core SDK only (pure stdlib — no extra dependencies)
pip install casfly-sdk
# With the HTTP service layer (FastAPI + uvicorn)
pip install casfly-sdk[service]
From source (editable install for development):
cd sdk
pip install -e .
pip install -e ".[service]" # also install service deps
How to Use CasFly with Two Devices (Smartwatch + Blood Pressure Cuff)
Use this flow when you have fragmented logs from multiple devices and want a probable precursor chain.
- Prepare historical transition counts as
(cause, effect, lag_bin) -> count. - Convert each device's local timestamped records into
TimedEventlists. - Build one local
TPHGper device using the same CPT. - Define a
ProbabilisticLookupTablefor routing (event_name -> next device). - Register all devices in
CasFlyOrchestrator. - Call
trace(start_device, start_event)and inspecthops+confidence_audit().
Runnable example:
cd sdk
PYTHONPATH=src python3 examples/smartwatch_bp_cuff_demo.py
Example file:
examples/smartwatch_bp_cuff_demo.py
How to map your own data:
- Smartwatch stream rows ->
TimedEvent(name=<event_label>, timestamp=<utc_datetime>) - Blood pressure cuff rows -> same
TimedEventformat - Historical cohort counts ->
ConditionalProbabilityTable.from_counts(...) - Routing knowledge ->
ProbabilisticLookupTable([(event, device_id, prob), ...])
Quick Integration Example
from datetime import datetime, timedelta
from casfly_sdk import (
CasFlyNode,
CasFlyOrchestrator,
ConditionalProbabilityTable,
ProbabilisticLookupTable,
TPHGBuilder,
TimedEvent,
)
# 1) Build lag-conditioned transition table from counts.
counts = {
("Medication Non-Compliance", "Missed Beta-Blockers", "0-7 days"): 30,
("Missed Beta-Blockers", "Hypertension", "0-7 days"): 25,
("Hypertension", "Elevated Blood Pressure", "0-7 days"): 20,
("Elevated Blood Pressure", "Elevated Heart Rate", "0-7 days"): 16,
("Elevated Heart Rate", "Heart Attack", "0-7 days"): 14,
}
cpt = ConditionalProbabilityTable.from_counts(counts)
# 2) Create local event logs and per-device TPHGs.
now = datetime.utcnow()
node_a_events = [
TimedEvent("Elevated Heart Rate", now - timedelta(hours=1.5)),
TimedEvent("Heart Attack", now),
]
node_b_events = [
TimedEvent("Hypertension", now - timedelta(hours=3)),
TimedEvent("Elevated Blood Pressure", now - timedelta(hours=2)),
]
node_c_events = [
TimedEvent("Medication Non-Compliance", now - timedelta(hours=6)),
TimedEvent("Missed Beta-Blockers", now - timedelta(hours=2.5)),
]
builder = TPHGBuilder(cpt)
tphg_a = builder.build(node_a_events)
tphg_b = builder.build(node_b_events)
tphg_c = builder.build(node_c_events)
# 3) Define app-level routing table (event -> next device probability).
plt = ProbabilisticLookupTable([
("Elevated Heart Rate", "smartwatch", 0.8),
("Hypertension", "bp_cuff", 0.9),
("Missed Beta-Blockers", "med_dispenser", 0.95),
])
# 4) Register nodes and run chain tracing.
orchestrator = CasFlyOrchestrator(max_hops=8)
orchestrator.register(CasFlyNode("hospital", tphg_a, plt))
orchestrator.register(CasFlyNode("bp_cuff", tphg_b, plt))
orchestrator.register(CasFlyNode("med_dispenser", tphg_c, plt))
orchestrator.register(CasFlyNode("smartwatch", tphg_b, plt))
result = orchestrator.trace(start_device="hospital", start_event="Heart Attack")
print(result.visited_devices)
print(result.chain_confidence)
for hop in result.hops:
print(hop)
Integration Model for Any Application
- Keep the SDK core unchanged.
- Adapt only these boundaries in your app:
- Local event source ->
list[TimedEvent] - Historical transitions ->
ConditionalProbabilityTable - Service routing metadata ->
ProbabilisticLookupTable - Transport layer (HTTP, gRPC, Kafka, MQTT) around
CasFlyNode.handle
- Local event source ->
Test
cd sdk
python3 -m unittest discover -s tests -p 'test_*.py' -v
Command-Line Interface
After installing, a casfly command is available with three subcommands.
casfly trace — run a chain trace from data files
casfly trace \
--device smartwatch examples/data/smartwatch_events.json \
--device bp_cuff examples/data/bp_cuff_events.fhir.json \
--routing examples/data/routing_table.csv \
--patient P001 \
--event "Arrhythmia Alert" \
--start-device smartwatch
Options:
| Flag | Default | Description |
|---|---|---|
--device ID FILE |
required | Device ID and event file (repeat for each device) |
--routing FILE |
required | Routing table CSV |
--patient |
required | Patient ID to trace |
--event |
required | Trigger event name |
--start-device |
required | Device to start from |
--max-hops |
8 | Maximum chain hops |
--max-lag-days |
730 | Max transition lag window (days) |
--format |
text | Output format: text | json | csv | dot |
--output FILE |
— | Write result to file (.json / .csv / .dot) |
casfly build-cache — pre-build TPHG .pkl files
Required for distributed device mode. One .pkl file per patient per device.
casfly build-cache \
--device smartwatch examples/data/smartwatch_events.json \
--device bp_cuff examples/data/bp_cuff_events.fhir.json \
--output ./tphg_cache/
# → tphg_cache/smartwatch/P001_tphg.pkl, P002_tphg.pkl, ...
# → tphg_cache/bp_cuff/P001_tphg.pkl, P002_tphg.pkl, ...
Requires joblib: pip install joblib.
casfly validate — check coverage before tracing
Catches misconfiguration early: missing PLT routes, uncovered transitions, absent TPHG cache files.
casfly validate \
--device smartwatch examples/data/smartwatch_events.json \
--routing examples/data/routing_table.csv \
--tphg-dir ./tphg_cache/smartwatch/
Exits with code 1 if any errors are found.
Export chain results
From Python, ChainResult can be exported to multiple formats:
result = orch.trace(start_device="smartwatch", start_event="Arrhythmia Alert")
result.export("chain.json") # JSON
result.export("chain.csv") # CSV — one row per hop
result.export("chain.dot") # Graphviz DOT — render with: dot -Tpng chain.dot -o chain.png
# Or get the string directly:
print(result.to_json())
print(result.to_csv())
print(result.to_dot())
Validate from Python
from casfly_sdk.validate import validate_all
report = validate_all(cohort, cpt, plt, tphg_dir="./tphg_cache/smartwatch/")
print(report)
if report.has_errors():
raise SystemExit(1)
Production HTTP Layer (FastAPI)
The HTTP service is a per-device management wrapper — raw patient data never leaves the device. Each device runs its own container/process; the causal chain flows between devices over UDP.
Smartwatch :8001 BPCuff :8002 CasFlyHub :8003
────────────────────────────────────────────────────────────
CasFlyDevice CasFlyDevice CasFlyDevice
│ <──── UDP chain packets (no raw data) ────> │
Service code lives in service/casfly_service.
API
| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
Liveness check |
| POST | /start |
Initialise this device (bind UDP port, load TPHG) |
| POST | /initiate |
Start causal chain tracing from this device |
| GET | /status |
Return device identity and port |
Run locally (one process per device)
cd sdk
pip install -e ".[service]"
# Start device 1
DEVICE_ID=BPCuff uvicorn casfly_service.app:app \
--app-dir service --host 0.0.0.0 --port 8001 &
# Start device 2
DEVICE_ID=Smartwatch uvicorn casfly_service.app:app \
--app-dir service --host 0.0.0.0 --port 8002 &
# Initialise each device (call POST /start on each)
curl -X POST http://localhost:8001/start \
-H "Content-Type: application/json" \
-d '{"device_id":"BPCuff","lookup_csv":"data/lookup.csv","tphg_dir":"data/tphg/BPCuff","filtered_patients_csv":"data/patients.csv"}'
# Trigger chain tracing from the initiator device
curl -X POST http://localhost:8002/initiate \
-H "Content-Type: application/json" \
-d '{"event":"Heart Attack","patient_id":"P001"}'
Docker (one container per device)
cd sdk
docker build -f service/Dockerfile -t casfly-service:0.1.0 .
# Each device is a separate container with its own data volume
docker run --rm -p 8001:8000 \
-e DEVICE_ID=BPCuff \
-v /your/data:/data \
casfly-service:0.1.0
docker run --rm -p 8002:8000 \
-e DEVICE_ID=Smartwatch \
-v /your/data:/data \
casfly-service:0.1.0
Citation
Please cite both the software repository and the CasFly paper.
@software{gupta_misra_casfly_repo_2026,
title = {CasFly: SDK, Service, and Reproducibility Pipeline},
author = {Gupta, Anshita and Misra, Sudip},
year = {2026},
url = {https://github.com/anshita510/CasFly},
version = {v0.1.0}
}
@ARTICLE{11250683,
author={Gupta, Anshita and Misra, Sudip},
journal={IEEE Internet of Things Journal},
title={CasFly: Causal Chain Tracing Across Fragmented Edge Data for IoT Healthcare},
year={2026},
volume={13},
number={3},
pages={4578-4586},
keywords={Medical services;Internet of Things;Probabilistic logic;Viterbi algorithm;Heuristic algorithms;Protocols;Heart rate;Real-time systems;Wearable Health Monitoring Systems;Object recognition;Causal chain tracing;decentralized protocols;edge computing;fragmented data;IoT healthcare;probabilistic graphs},
doi={10.1109/JIOT.2025.3633292}
}
IEEE Xplore: https://ieeexplore.ieee.org/document/11250683/
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file casfly_sdk-0.1.0.tar.gz.
File metadata
- Download URL: casfly_sdk-0.1.0.tar.gz
- Upload date:
- Size: 44.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3fa9873e1011293b298892d5f9fcf840dd5d0dad2398e6c170fbc48cfbe8195
|
|
| MD5 |
bfee084f1d961ca25ae46726ee3ce734
|
|
| BLAKE2b-256 |
304f25e8b7a47cb424ceaa9ba8543126997a5dfdae431d5c32e5755d5f8bdff0
|
File details
Details for the file casfly_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: casfly_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 36.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6264d74b5b421f51e9d5d242dd5078913dd5a58590caee9d4ad12b5d3d09206a
|
|
| MD5 |
05a092d10901620d36543aeaf0a26a23
|
|
| BLAKE2b-256 |
82c08d91a192e1cbde13ca9ffa2eef1b17849444aa48969dc91bf9adb2b826aa
|