chathurvitha commited on
Commit
d43715d
·
1 Parent(s): adc77b7

grader&rewards

Browse files
Files changed (2) hide show
  1. grader.py +120 -0
  2. rewards.py +92 -0
grader.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Grader module for the Cat Rescue Reinforcement Learning environment.
3
+ Evaluates agent performance based on episode logs.
4
+ """
5
+
6
+ class CatRescueGrader:
7
+ """
8
+ Evaluates an episode log from the Cat Rescue environment and produces
9
+ structured grading results and human-readable summaries.
10
+ """
11
+
12
+ def grade(self, episode_log: dict) -> dict:
13
+ """
14
+ Grades an episode based on the provided episode log.
15
+
16
+ Args:
17
+ episode_log (dict): A dictionary containing:
18
+ - total_steps (int): Total steps taken by the agent.
19
+ - cats_rescued (int): Number of cats successfully rescued.
20
+ - total_cats (int): Total number of cats in the episode.
21
+ - total_reward (float): Total reward accumulated.
22
+ - hit_walls (int): Number of times the agent hit a wall.
23
+ - rescue_log (list of bool): True if rescued, one per cat.
24
+
25
+ Returns:
26
+ dict: A structured evaluation result containing:
27
+ - cats_rescued_count (int)
28
+ - all_cats_rescued (bool)
29
+ - rescue_details (list of dict)
30
+ - total_steps (int)
31
+ - wall_hits (int)
32
+ - total_reward (float)
33
+ - efficiency_score (float)
34
+ - passed (bool)
35
+ - grade_label (str)
36
+ """
37
+ total_steps = episode_log.get("total_steps", 0)
38
+ cats_rescued = episode_log.get("cats_rescued", 0)
39
+ total_cats = episode_log.get("total_cats", 0)
40
+ total_reward = episode_log.get("total_reward", 0.0)
41
+ hit_walls = episode_log.get("hit_walls", 0)
42
+ rescue_log = episode_log.get("rescue_log", [])
43
+
44
+ all_cats_rescued = (cats_rescued == total_cats) and (total_cats > 0)
45
+ passed = all_cats_rescued
46
+
47
+ rescue_details = [{"cat_id": i, "rescued": rescued} for i, rescued in enumerate(rescue_log)]
48
+
49
+ efficiency_score = 0.0
50
+ if total_steps > 0:
51
+ efficiency_score = min(1.0, float(cats_rescued) / total_steps)
52
+
53
+ if passed and efficiency_score >= 0.8:
54
+ grade_label = "PERFECT"
55
+ elif passed and efficiency_score >= 0.5:
56
+ grade_label = "GOOD"
57
+ elif cats_rescued > 0 and not passed:
58
+ grade_label = "PARTIAL"
59
+ elif cats_rescued == 0:
60
+ grade_label = "FAIL"
61
+ else:
62
+ # Fallback if passed but efficiency < 0.5
63
+ grade_label = "PASS"
64
+
65
+ return {
66
+ "cats_rescued_count": cats_rescued,
67
+ "all_cats_rescued": all_cats_rescued,
68
+ "rescue_details": rescue_details,
69
+ "total_steps": total_steps,
70
+ "wall_hits": hit_walls,
71
+ "total_reward": total_reward,
72
+ "efficiency_score": efficiency_score,
73
+ "passed": passed,
74
+ "grade_label": grade_label
75
+ }
76
+
77
+ def summary(self, grade_result: dict) -> str:
78
+ """
79
+ Generates a human-readable summary of the evaluation result.
80
+
81
+ Args:
82
+ grade_result (dict): The result dictionary produced by the grade method.
83
+
84
+ Returns:
85
+ str: A formatted summary string.
86
+ """
87
+ status = "PASSED" if grade_result.get("passed") else "FAILED"
88
+ grade_label = grade_result.get("grade_label", "UNKNOWN")
89
+ cats_rescued = grade_result.get("cats_rescued_count", 0)
90
+ total_steps = grade_result.get("total_steps", 0)
91
+ efficiency = grade_result.get("efficiency_score", 0.0)
92
+
93
+ return (
94
+ f"--- Grader Summary ---\n"
95
+ f"Status: {status}\n"
96
+ f"Grade Label: {grade_label}\n"
97
+ f"Cats Rescued: {cats_rescued}\n"
98
+ f"Total Steps: {total_steps}\n"
99
+ f"Efficiency Score: {efficiency:.2f}\n"
100
+ f"----------------------"
101
+ )
102
+
103
+
104
+ if __name__ == "__main__":
105
+ sample_log = {
106
+ "total_steps": 5,
107
+ "cats_rescued": 3,
108
+ "total_cats": 3,
109
+ "total_reward": 15.5,
110
+ "hit_walls": 1,
111
+ "rescue_log": [True, True, True]
112
+ }
113
+
114
+ grader = CatRescueGrader()
115
+ result = grader.grade(sample_log)
116
+ print("Structured Result:")
117
+ import json
118
+ print(json.dumps(result, indent=2))
119
+ print("\nSummary:")
120
+ print(grader.summary(result))
rewards.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Rewards module for the Cat Rescue Reinforcement Learning environment.
3
+ Defines reward constants and computes rewards for different agent events.
4
+ """
5
+
6
+ class CatRescueRewards:
7
+ """
8
+ Manages and calculates rewards for the Cat Rescue environment.
9
+ """
10
+ STEP_PENALTY = -0.1
11
+ WALL_HIT_PENALTY = -0.3
12
+ CAT_RESCUED_REWARD = 1.0
13
+ ALL_CATS_BONUS = 2.0
14
+
15
+ def calculate(self, event: str, context: dict = None) -> float:
16
+ """
17
+ Calculates the appropriate reward for an event.
18
+
19
+ Args:
20
+ event (str): The name of the event ("step", "wall_hit", "cat_rescued", "all_cats_rescued").
21
+ context (dict, optional): Additional context for the event (e.g., cats_remaining). Defaults to None.
22
+
23
+ Returns:
24
+ float: The reward value for the selected event. Returns 0.0 for unknown events.
25
+ """
26
+ if context is None:
27
+ context = {}
28
+
29
+ if event == "step":
30
+ return self.STEP_PENALTY
31
+ elif event == "wall_hit":
32
+ return self.WALL_HIT_PENALTY
33
+ elif event == "cat_rescued":
34
+ return self.CAT_RESCUED_REWARD
35
+ elif event == "all_cats_rescued":
36
+ # If all cats rescued, return CAT_RESCUED_REWARD plus ALL_CATS_BONUS combined
37
+ return self.CAT_RESCUED_REWARD + self.ALL_CATS_BONUS
38
+ else:
39
+ return 0.0
40
+
41
+ def calculate_episode_total(self, events: list) -> float:
42
+ """
43
+ Calculates the total cumulative reward for a list of event strings.
44
+
45
+ Args:
46
+ events (list of str): A list of event strings that occurred during an episode.
47
+
48
+ Returns:
49
+ float: The total reward accumulated, rounded to 2 decimal places.
50
+ """
51
+ total_reward = 0.0
52
+ for event in events:
53
+ total_reward += self.calculate(event)
54
+ return round(total_reward, 2)
55
+
56
+ def get_reward_table(self) -> dict:
57
+ """
58
+ Retrieves a dictionary mapping of all reward constants.
59
+
60
+ Returns:
61
+ dict: The configured reward values for display or debugging purposes.
62
+ """
63
+ return {
64
+ "STEP_PENALTY": self.STEP_PENALTY,
65
+ "WALL_HIT_PENALTY": self.WALL_HIT_PENALTY,
66
+ "CAT_RESCUED_REWARD": self.CAT_RESCUED_REWARD,
67
+ "ALL_CATS_BONUS": self.ALL_CATS_BONUS
68
+ }
69
+
70
+
71
+ if __name__ == "__main__":
72
+ rewards = CatRescueRewards()
73
+
74
+ print("--- Reward Table ---")
75
+ for key, value in rewards.get_reward_table().items():
76
+ print(f"{key}: {value:>5}")
77
+
78
+ print("\n--- Single Event Calculations ---")
79
+ print(f"step: {rewards.calculate('step')}")
80
+ print(f"wall_hit: {rewards.calculate('wall_hit')}")
81
+ print(f"cat_rescued: {rewards.calculate('cat_rescued', {'cats_remaining': 1})}")
82
+ print(f"all_cats_rescued: {rewards.calculate('all_cats_rescued', {'cats_remaining': 0})}")
83
+ print(f"unknown_event: {rewards.calculate('sleep')}")
84
+
85
+ print("\n--- Episode Total Calculation ---")
86
+ sample_events = [
87
+ "step", "step", "wall_hit", "step",
88
+ "cat_rescued", "step", "step", "all_cats_rescued"
89
+ ]
90
+ total = rewards.calculate_episode_total(sample_events)
91
+ print(f"Events: {sample_events}")
92
+ print(f"Total Cumulative Reward: {total}")