saferl-lite 0.1.0__tar.gz

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 (36) hide show
  1. saferl_lite-0.1.0/LICENSE +21 -0
  2. saferl_lite-0.1.0/MANIFEST.in +5 -0
  3. saferl_lite-0.1.0/PKG-INFO +139 -0
  4. saferl_lite-0.1.0/README.md +87 -0
  5. saferl_lite-0.1.0/agents/__init__.py +0 -0
  6. saferl_lite-0.1.0/agents/constrained_dqn.py +82 -0
  7. saferl_lite-0.1.0/agents/constraints.py +39 -0
  8. saferl_lite-0.1.0/docs/about.md +65 -0
  9. saferl_lite-0.1.0/docs/docs/index.md +34 -0
  10. saferl_lite-0.1.0/docs/evaluation/metrics.md +113 -0
  11. saferl_lite-0.1.0/docs/examples/cartpole.md +84 -0
  12. saferl_lite-0.1.0/docs/explainability/saliency.md +90 -0
  13. saferl_lite-0.1.0/docs/explainability/shap.md +85 -0
  14. saferl_lite-0.1.0/docs/mkdocs.yml +54 -0
  15. saferl_lite-0.1.0/docs/reference/agents.md +54 -0
  16. saferl_lite-0.1.0/docs/reference/constraints.md +57 -0
  17. saferl_lite-0.1.0/docs/reference/envs.md +66 -0
  18. saferl_lite-0.1.0/docs/reference.md +35 -0
  19. saferl_lite-0.1.0/docs/usage/installation.md +54 -0
  20. saferl_lite-0.1.0/docs/usage/quickstart.md +48 -0
  21. saferl_lite-0.1.0/envs/__init__.py +0 -0
  22. saferl_lite-0.1.0/envs/wrappers.py +58 -0
  23. saferl_lite-0.1.0/explainability/__init__.py +0 -0
  24. saferl_lite-0.1.0/explainability/saliency.py +23 -0
  25. saferl_lite-0.1.0/explainability/shap_explainer.py +31 -0
  26. saferl_lite-0.1.0/requirements.txt +23 -0
  27. saferl_lite-0.1.0/saferl_lite.egg-info/PKG-INFO +139 -0
  28. saferl_lite-0.1.0/saferl_lite.egg-info/SOURCES.txt +34 -0
  29. saferl_lite-0.1.0/saferl_lite.egg-info/dependency_links.txt +1 -0
  30. saferl_lite-0.1.0/saferl_lite.egg-info/requires.txt +22 -0
  31. saferl_lite-0.1.0/saferl_lite.egg-info/top_level.txt +3 -0
  32. saferl_lite-0.1.0/setup.cfg +4 -0
  33. saferl_lite-0.1.0/setup.py +28 -0
  34. saferl_lite-0.1.0/tests/test_constraints.py +17 -0
  35. saferl_lite-0.1.0/tests/test_metrics.py +18 -0
  36. saferl_lite-0.1.0/tests/test_safe_env.py +11 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Satyam Mishra
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ include README.md
2
+ include requirements.txt
3
+ include LICENSE
4
+ recursive-include saferl_lite *.py
5
+ recursive-include docs *
@@ -0,0 +1,139 @@
1
+ Metadata-Version: 2.4
2
+ Name: saferl-lite
3
+ Version: 0.1.0
4
+ Summary: A lightweight, explainable, and constrained reinforcement learning toolkit.
5
+ Home-page: https://github.com/satyamcser/saferl-lite
6
+ Author: Satyam Mishra
7
+ Author-email: satyam@example.com
8
+ Project-URL: Documentation, https://satyamcser.github.io/saferl-lite/
9
+ Project-URL: Source, https://github.com/satyamcser/saferl-lite
10
+ Project-URL: Bug Tracker, https://github.com/satyamcser/saferl-lite/issues
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: gym
20
+ Requires-Dist: gymnasium
21
+ Requires-Dist: numpy
22
+ Requires-Dist: torch
23
+ Requires-Dist: matplotlib
24
+ Requires-Dist: seaborn
25
+ Requires-Dist: pre-commit
26
+ Requires-Dist: flake8
27
+ Requires-Dist: pyyaml
28
+ Requires-Dist: shap
29
+ Requires-Dist: captum
30
+ Requires-Dist: typer
31
+ Requires-Dist: scikit-learn
32
+ Requires-Dist: pandas
33
+ Requires-Dist: pytest
34
+ Requires-Dist: pytest-cov
35
+ Requires-Dist: coverage
36
+ Requires-Dist: mkdocs
37
+ Requires-Dist: wandb
38
+ Requires-Dist: mkdocs>=1.5
39
+ Requires-Dist: mkdocs-material>=9.5
40
+ Requires-Dist: mkdocstrings[python]
41
+ Dynamic: author
42
+ Dynamic: author-email
43
+ Dynamic: classifier
44
+ Dynamic: description
45
+ Dynamic: description-content-type
46
+ Dynamic: home-page
47
+ Dynamic: license-file
48
+ Dynamic: project-url
49
+ Dynamic: requires-dist
50
+ Dynamic: requires-python
51
+ Dynamic: summary
52
+
53
+ # ๐Ÿ” SafeRL-Lite
54
+
55
+ A **lightweight, explainable, and modular** Python library for **Constrained Reinforcement Learning (Safe RL)** with real-time **SHAP & saliency-based explainability**, custom metrics, and Gym-compatible wrappers.
56
+
57
+ <p align="center">
58
+ <img src="https://img.shields.io/github/license/satyamcser/saferl-lite?style=flat-square">
59
+ <img src="https://img.shields.io/github/stars/satyamcser/saferl-lite?style=flat-square">
60
+ <img src="https://img.shields.io/pypi/v/saferl-lite?style=flat-square">
61
+ <img src="https://img.shields.io/github/actions/workflow/status/satyamcser/saferl-lite/ci.yml?branch=main&style=flat-square">
62
+ </p>
63
+
64
+ ---
65
+
66
+ ## ๐ŸŒŸ Overview
67
+
68
+ **SafeRL-Lite** empowers reinforcement learning agents to act under **safety constraints**, while remaining **interpretable** and **modular** for fast experimentation. It wraps standard Gym environments and DQN-based agents with:
69
+
70
+ - โœ… Safety constraint logic
71
+ - ๐Ÿ” Visual explainability (SHAP, saliency maps)
72
+ - ๐Ÿ“Š Violation and reward tracking
73
+ - ๐Ÿงช Built-in testing and evaluations
74
+
75
+ ---
76
+
77
+ ## ๐Ÿ”ง Installation
78
+
79
+ > ๐Ÿ“ฆ PyPI (coming soon)
80
+ ```bash
81
+ pip install saferl-lite
82
+ ```
83
+
84
+ ## ๐Ÿ› ๏ธ From source:
85
+
86
+ ```bash
87
+ git clone https://github.com/satyamcser/saferl-lite.git
88
+ cd saferl-lite
89
+ pip install -e .
90
+ ```
91
+
92
+ ## ๐Ÿš€ Quickstart
93
+ Train a constrained DQN agent with saliency-based explainability:
94
+
95
+ ```bash
96
+ python train.py --env CartPole-v1 --constraint pole_angle --explain shap
97
+ ```
98
+
99
+ ๐Ÿ”น This:
100
+
101
+ - Adds a pole-angle constraint wrapper to the Gym env
102
+
103
+ - Logs violations
104
+
105
+ - Displays SHAP or saliency explanations for agent decisions
106
+
107
+ ## ๐Ÿง  Features
108
+ #### โœ… Constrained RL
109
+ - Add custom constraints via wrapper or logic class
110
+
111
+ - Violation logging and reward shaping
112
+
113
+ - Safe vs unsafe episode tracking
114
+
115
+ #### ๐Ÿ” Explainability
116
+ - SaliencyExplainer โ€” gradient-based visual heatmaps
117
+
118
+ - SHAPExplainer โ€” feature contribution values per decision
119
+
120
+ - Compatible with any PyTorch-based agent
121
+
122
+ #### ๐Ÿ“Š Metrics
123
+ - Constraint violation rate
124
+
125
+ - Episode reward
126
+
127
+ - Cumulative safe reward
128
+
129
+ - Action entropy & temporal behavior stats
130
+
131
+ #### ๐Ÿ“š Modularity
132
+ - Swap out agents, constraints, evaluators, or explainers
133
+
134
+ - Supports Gym environments
135
+
136
+ - Configurable training pipeline
137
+
138
+ ## ๐Ÿ“œ Citation
139
+ Coming soon after arXiv/preprint release.
@@ -0,0 +1,87 @@
1
+ # ๐Ÿ” SafeRL-Lite
2
+
3
+ A **lightweight, explainable, and modular** Python library for **Constrained Reinforcement Learning (Safe RL)** with real-time **SHAP & saliency-based explainability**, custom metrics, and Gym-compatible wrappers.
4
+
5
+ <p align="center">
6
+ <img src="https://img.shields.io/github/license/satyamcser/saferl-lite?style=flat-square">
7
+ <img src="https://img.shields.io/github/stars/satyamcser/saferl-lite?style=flat-square">
8
+ <img src="https://img.shields.io/pypi/v/saferl-lite?style=flat-square">
9
+ <img src="https://img.shields.io/github/actions/workflow/status/satyamcser/saferl-lite/ci.yml?branch=main&style=flat-square">
10
+ </p>
11
+
12
+ ---
13
+
14
+ ## ๐ŸŒŸ Overview
15
+
16
+ **SafeRL-Lite** empowers reinforcement learning agents to act under **safety constraints**, while remaining **interpretable** and **modular** for fast experimentation. It wraps standard Gym environments and DQN-based agents with:
17
+
18
+ - โœ… Safety constraint logic
19
+ - ๐Ÿ” Visual explainability (SHAP, saliency maps)
20
+ - ๐Ÿ“Š Violation and reward tracking
21
+ - ๐Ÿงช Built-in testing and evaluations
22
+
23
+ ---
24
+
25
+ ## ๐Ÿ”ง Installation
26
+
27
+ > ๐Ÿ“ฆ PyPI (coming soon)
28
+ ```bash
29
+ pip install saferl-lite
30
+ ```
31
+
32
+ ## ๐Ÿ› ๏ธ From source:
33
+
34
+ ```bash
35
+ git clone https://github.com/satyamcser/saferl-lite.git
36
+ cd saferl-lite
37
+ pip install -e .
38
+ ```
39
+
40
+ ## ๐Ÿš€ Quickstart
41
+ Train a constrained DQN agent with saliency-based explainability:
42
+
43
+ ```bash
44
+ python train.py --env CartPole-v1 --constraint pole_angle --explain shap
45
+ ```
46
+
47
+ ๐Ÿ”น This:
48
+
49
+ - Adds a pole-angle constraint wrapper to the Gym env
50
+
51
+ - Logs violations
52
+
53
+ - Displays SHAP or saliency explanations for agent decisions
54
+
55
+ ## ๐Ÿง  Features
56
+ #### โœ… Constrained RL
57
+ - Add custom constraints via wrapper or logic class
58
+
59
+ - Violation logging and reward shaping
60
+
61
+ - Safe vs unsafe episode tracking
62
+
63
+ #### ๐Ÿ” Explainability
64
+ - SaliencyExplainer โ€” gradient-based visual heatmaps
65
+
66
+ - SHAPExplainer โ€” feature contribution values per decision
67
+
68
+ - Compatible with any PyTorch-based agent
69
+
70
+ #### ๐Ÿ“Š Metrics
71
+ - Constraint violation rate
72
+
73
+ - Episode reward
74
+
75
+ - Cumulative safe reward
76
+
77
+ - Action entropy & temporal behavior stats
78
+
79
+ #### ๐Ÿ“š Modularity
80
+ - Swap out agents, constraints, evaluators, or explainers
81
+
82
+ - Supports Gym environments
83
+
84
+ - Configurable training pipeline
85
+
86
+ ## ๐Ÿ“œ Citation
87
+ Coming soon after arXiv/preprint release.
File without changes
@@ -0,0 +1,82 @@
1
+ # agents/constrained_dqn.py
2
+
3
+ import numpy as np
4
+ import random
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.optim as optim
8
+ from collections import deque
9
+ from agents.constraints import Constraint
10
+
11
+
12
+ class DQNetwork(nn.Module):
13
+ def __init__(self, input_dim, output_dim):
14
+ super().__init__()
15
+ self.net = nn.Sequential(
16
+ nn.Linear(input_dim, 128),
17
+ nn.ReLU(),
18
+ nn.Linear(128, 128),
19
+ nn.ReLU(),
20
+ nn.Linear(128, output_dim),
21
+ )
22
+
23
+ def forward(self, x):
24
+ return self.net(x)
25
+
26
+
27
+ class ConstrainedDQNAgent:
28
+ def __init__(self, state_dim, action_dim, constraint: Constraint = None):
29
+ self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
30
+ self.q_net = DQNetwork(state_dim, action_dim).to(self.device)
31
+ self.target_net = DQNetwork(state_dim, action_dim).to(self.device)
32
+ self.target_net.load_state_dict(self.q_net.state_dict())
33
+
34
+ self.optimizer = optim.Adam(self.q_net.parameters(), lr=1e-3)
35
+ self.memory = deque(maxlen=10000)
36
+ self.gamma = 0.99
37
+ self.batch_size = 64
38
+
39
+ self.constraint = constraint
40
+ self.action_dim = action_dim
41
+
42
+ def select_action(self, state, epsilon):
43
+ if random.random() < epsilon:
44
+ return random.randint(0, self.action_dim - 1)
45
+ state = torch.tensor(state, dtype=torch.float32).to(self.device)
46
+ with torch.no_grad():
47
+ q_values = self.q_net(state)
48
+ return q_values.argmax().item()
49
+
50
+ def store_transition(self, s, a, r, s_next, done):
51
+ self.memory.append((s, a, r, s_next, done))
52
+
53
+ def update(self):
54
+ if len(self.memory) < self.batch_size:
55
+ return
56
+ batch = random.sample(self.memory, self.batch_size)
57
+ s, a, r, s_next, done = zip(*batch)
58
+
59
+ s = torch.tensor(s, dtype=torch.float32).to(self.device)
60
+ a = torch.tensor(a).to(self.device)
61
+ r = torch.tensor(r, dtype=torch.float32).to(self.device)
62
+ s_next = torch.tensor(s_next, dtype=torch.float32).to(self.device)
63
+ done = torch.tensor(done, dtype=torch.float32).to(self.device)
64
+
65
+ q_values = self.q_net(s).gather(1, a.unsqueeze(1)).squeeze()
66
+ with torch.no_grad():
67
+ target_q = r + self.gamma * self.target_net(s_next).max(1)[0] * (1 - done)
68
+
69
+ loss = nn.functional.mse_loss(q_values, target_q)
70
+ self.optimizer.zero_grad()
71
+ loss.backward()
72
+ self.optimizer.step()
73
+
74
+ def apply_constraint(self, state, action, reward):
75
+ if self.constraint:
76
+ penalty = self.constraint.compute_penalty(state, action, reward)
77
+ return reward - penalty, penalty
78
+ return reward, 0.0
79
+
80
+ def reset_constraints(self):
81
+ if self.constraint:
82
+ self.constraint.reset()
@@ -0,0 +1,39 @@
1
+ # agents/constraints.py
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+
6
+ class Constraint(ABC):
7
+ """Abstract base class for constraints in SafeRL agents."""
8
+
9
+ @abstractmethod
10
+ def compute_penalty(self, state, action, reward) -> float:
11
+ """Return penalty value for a given step."""
12
+ pass
13
+
14
+ def reset(self):
15
+ """Optional: reset internal counters for new episode."""
16
+ pass
17
+
18
+
19
+ class ActionBudgetConstraint(Constraint):
20
+ def __init__(self, max_actions: int):
21
+ self.max_actions = max_actions
22
+ self.counter = 0
23
+
24
+ def compute_penalty(self, state, action, reward) -> float:
25
+ self.counter += 1
26
+ return 1.0 if self.counter > self.max_actions else 0.0
27
+
28
+ def reset(self):
29
+ self.counter = 0
30
+
31
+
32
+ class EnergyPenaltyConstraint(Constraint):
33
+ def __init__(self, energy_fn, max_energy):
34
+ self.energy_fn = energy_fn
35
+ self.max_energy = max_energy
36
+
37
+ def compute_penalty(self, state, action, reward) -> float:
38
+ energy = self.energy_fn(state, action)
39
+ return max(0.0, energy - self.max_energy)
@@ -0,0 +1,65 @@
1
+ # ๐Ÿ™Œ About SafeRL-Lite
2
+
3
+ **SafeRL-Lite** is a lightweight, explainable, and modular Python library for constrained reinforcement learning (Safe RL). It is designed for researchers, educators, and engineers who want to build safe, interpretable agents in Gym-compatible environments with minimal setup.
4
+
5
+ ---
6
+
7
+ ## ๐ŸŽฏ Mission
8
+
9
+ SafeRL-Lite aims to:
10
+ - Enable **constrained RL** with built-in safety logic.
11
+ - Support **real-time explainability** using SHAP and saliency maps.
12
+ - Provide **modular components** for easy experimentation and extension.
13
+ - Be **minimal**, **readable**, and **production-friendly**.
14
+
15
+ ---
16
+
17
+ ## ๐Ÿงฑ Key Components
18
+
19
+ - **Constrained DQN agent** with runtime violation tracking.
20
+ - **Environment wrappers** for safety constraints and logging.
21
+ - **Evaluation module** to track rewards, constraint violations, and success metrics.
22
+ - **Explainability tools**:
23
+ - Gradient-based **saliency maps**
24
+ - **SHAP** values for input importance
25
+
26
+ ---
27
+
28
+ ## ๐Ÿ‘ฉโ€๐Ÿ”ฌ Who Should Use This?
29
+
30
+ SafeRL-Lite is ideal for:
31
+ - ๐Ÿ“š **Educators** teaching RL and safety concepts.
32
+ - ๐Ÿ”ฌ **Researchers** in safe RL, explainable AI (XAI), or constrained optimization.
33
+ - ๐Ÿงช **Experimenters** building proof-of-concepts for safety-critical environments (e.g., healthcare, robotics).
34
+
35
+ ---
36
+
37
+ ## ๐Ÿ› ๏ธ Design Philosophy
38
+
39
+ - โœ… Simplicity over complexity
40
+ - ๐Ÿงฉ Component reusability
41
+ - ๐Ÿ” Built-in explainability
42
+ - ๐Ÿงช Test-driven development
43
+ - ๐Ÿ“ฆ PyPI-ready structure
44
+
45
+ ---
46
+
47
+ ## ๐Ÿค Contributing
48
+
49
+ We welcome contributions from the community! Check out the [CONTRIBUTING.md](https://github.com/satyamcser/saferl-lite/blob/main/CONTRIBUTING.md) for guidelines.
50
+
51
+ ---
52
+
53
+ ## ๐Ÿ“œ License
54
+
55
+ This project is licensed under the **MIT License**. See the [LICENSE](https://github.com/satyamcser/saferl-lite/blob/main/LICENSE) file for details.
56
+
57
+ ---
58
+
59
+ ## ๐ŸŒ Links
60
+
61
+ - GitHub: [https://github.com/satyamcser/saferl-lite](https://github.com/satyamcser/saferl-lite)
62
+ - PyPI: *Coming soon*
63
+ - Docs: *This site*
64
+
65
+ ---
@@ -0,0 +1,34 @@
1
+ # SafeRL-Lite
2
+
3
+ Welcome to **SafeRL-Lite**, a lightweight, explainable, and constrained reinforcement learning library built in Python.
4
+
5
+ ---
6
+
7
+ ## โœจ Features
8
+
9
+ - โ™ป๏ธ **Constrained Agents**: Supports safe training using budgeted penalties and constraint wrappers.
10
+ - ๐Ÿ” **Explainability Tools**: Includes SHAP and saliency-based attribution methods.
11
+ - ๐ŸŽฎ **Custom Environments**: Easy wrappers for constraint-aware OpenAI Gym environments.
12
+ - ๐Ÿ“Š **Evaluation Metrics**: Regret, safe episode rate, violation count.
13
+ - ๐Ÿงช **Tested and Documented**: Full unit test suite with CI + MkDocs support.
14
+
15
+ ---
16
+
17
+ ## ๐Ÿ”ง Repository Info
18
+
19
+ - **Author**: [Satyam Mishra](https://github.com/satyamcser)
20
+ - **GitHub**: [github.com/satyamcser/saferl-lite](https://github.com/satyamcser/saferl-lite)
21
+
22
+ ---
23
+
24
+ ## ๐Ÿ“ฆ Installation
25
+
26
+ See [Usage โ†’ Installation](usage/installation.md) for details.
27
+
28
+ ## ๐Ÿš€ Quickstart
29
+
30
+ See [Usage โ†’ Quickstart](usage/quickstart.md) to get up and running in 60 seconds.
31
+
32
+ ## ๐Ÿงช Example
33
+
34
+ - [CartPole with Constraints](examples/cartpole.md)
@@ -0,0 +1,113 @@
1
+ # ๐Ÿ“Š SafeRL-Lite Evaluation Metrics
2
+
3
+ SafeRL-Lite provides built-in evaluation metrics to assess both **performance** and **safety** of RL agents in constrained environments.
4
+
5
+ ---
6
+
7
+ ## ๐ŸŽฏ 1. `evaluate_safety_violations`
8
+
9
+ ```python
10
+ evaluate_safety_violations(violations: List[int]) -> float
11
+ ```
12
+
13
+ #### Description:
14
+ Calculates the percentage of time steps where the agent violated a safety constraint.
15
+
16
+ #### Arguments:
17
+
18
+ - violations (List[int]): A binary list where 1 indicates a violation at that timestep.
19
+
20
+ Returns:
21
+
22
+ - float: Fraction of violated steps (e.g. 0.12 means 12% violation rate).
23
+
24
+ ### Usage Example:
25
+
26
+ ```python
27
+ violations = [0, 1, 0, 1, 1]
28
+ violation_rate = evaluate_safety_violations(violations)
29
+ # Output: 0.6
30
+ ```
31
+ ---
32
+
33
+ ## ๐Ÿ“ˆ 2. evaluate_cumulative_reward
34
+
35
+ ```python
36
+ evaluate_cumulative_reward(rewards: List[float]) -> float
37
+
38
+ ```
39
+
40
+ #### Description:
41
+ Computes the total accumulated reward across an episode.
42
+
43
+ #### Arguments:
44
+
45
+ - rewards (List[float]): A list of numerical rewards at each timestep.
46
+
47
+ Returns:
48
+
49
+ - float: Total reward over the episode.
50
+
51
+ ### Usage Example:
52
+
53
+ ```python
54
+ rewards = [1.0, -0.2, 2.0, 0.5]
55
+ total_reward = evaluate_cumulative_reward(rewards)
56
+ # Output: 3.3
57
+ ```
58
+
59
+
60
+ ---
61
+
62
+ ## โš–๏ธ 3. evaluate_constraint_satisfaction_rate
63
+
64
+ ```python
65
+ evaluate_constraint_satisfaction_rate(satisfied: List[bool]) -> float
66
+ ```
67
+
68
+ #### Description:
69
+ Measures the fraction of time steps where all constraints were satisfied.
70
+
71
+ #### Arguments:
72
+
73
+ - satisfied (List[bool]): A list where True means constraints were satisfied at that step.
74
+
75
+ Returns:
76
+
77
+ - float: Constraint satisfaction rate (e.g. 0.9 means 90% of steps were constraint-safe).
78
+
79
+ ### Usage Example:
80
+
81
+ ```python
82
+ satisfied = [True, False, True, True]
83
+ rate = evaluate_constraint_satisfaction_rate(satisfied)
84
+ # Output: 0.75
85
+
86
+ ```
87
+
88
+
89
+
90
+ ---
91
+
92
+ ## ๐Ÿ“Š 4. Visualization Hooks (WIP)
93
+
94
+ Future versions will include utilities for:
95
+
96
+ - Violation trend plots
97
+
98
+ - Reward-violation scatter plots
99
+
100
+ - Safety-performance Pareto frontiers
101
+
102
+ #### ๐Ÿง  Pro Tip
103
+ These metrics are modular, you can log them live during training or compute them post hoc from rollout logs using:
104
+
105
+ ```python
106
+ from evaluations.metrics import (
107
+ evaluate_safety_violations,
108
+ evaluate_cumulative_reward,
109
+ evaluate_constraint_satisfaction_rate,
110
+ )
111
+
112
+ ```
113
+
@@ -0,0 +1,84 @@
1
+ # ๐Ÿงช Example: Safe CartPole
2
+
3
+ This example demonstrates how to train a **constrained DQN agent** on the classic `CartPole-v1` task with constraint-aware wrappers, SHAP-based explainability, and safe policy evaluation.
4
+
5
+ ---
6
+
7
+ ## ๐Ÿง  Objective
8
+
9
+ Balance the pole while **minimizing unsafe actions**, defined by custom constraints (e.g., excessive cart velocity).
10
+
11
+ ---
12
+
13
+ ## ๐Ÿ“ฆ Setup
14
+
15
+ Make sure youโ€™ve followed the [Installation Guide](../usage/installation.md).
16
+
17
+ ---
18
+
19
+ ## ๐Ÿ”ง 1. Import Required Modules
20
+
21
+ ```python
22
+ import gymnasium as gym
23
+ from agents.constrained_dqn import ConstrainedDQNAgent
24
+ from envs.wrappers import ConstraintWrapper
25
+ from evaluations.metrics import evaluate_agent
26
+ from explainability.shap_explainer import SHAPExplainer
27
+ ```
28
+
29
+ ---
30
+
31
+ ## ๐Ÿ—๏ธ 2. Create a Safe Environment
32
+
33
+ ```python
34
+ env = gym.make("CartPole-v1", render_mode=None)
35
+ safe_env = ConstraintWrapper(env, constraint_threshold=0.5)
36
+
37
+ ```
38
+
39
+ ---
40
+
41
+ ## ๐Ÿค– 3. Train a Constrained Agent
42
+
43
+ ```python
44
+ agent = ConstrainedDQNAgent(env=safe_env, budget=1.0)
45
+ agent.train(episodes=10)
46
+
47
+
48
+ ```
49
+
50
+ ---
51
+
52
+ ## ๐Ÿ“Š 4. Evaluate the Agent
53
+
54
+ ```python
55
+ metrics = evaluate_agent(agent, safe_env, episodes=5)
56
+
57
+ print("=== Evaluation Metrics ===")
58
+ print("Safe episode rate:", metrics["safe_rate"])
59
+ print("Average violations:", metrics["avg_violations"])
60
+ print("Total regret:", metrics["regret"])
61
+
62
+ ```
63
+
64
+ ---
65
+
66
+ ## ๐Ÿ” 5. Explain a Sample Episode with SHAP
67
+
68
+ ```python
69
+ explainer = SHAPExplainer(agent, safe_env)
70
+ explainer.explain_episode(max_steps=50)
71
+ ```
72
+
73
+ ---
74
+
75
+ ## โœ… Output Snapshot
76
+
77
+ ```bash
78
+ Episode 3: reward=1.0, penalty=0.0, violations=0.0
79
+ SHAP: ['0.04', '0.01']
80
+ Saliency: ['0.19', '0.05']
81
+
82
+ ```
83
+
84
+ ---