Abhishek-CS221006 commited on
Commit
11387bb
·
verified ·
1 Parent(s): fb37416

Update env.py

Browse files
Files changed (1) hide show
  1. env.py +66 -27
env.py CHANGED
@@ -90,6 +90,9 @@ class ClinicalTrialEnvironment(
90
  ) -> ClinicalTrialObservation:
91
  del seed, kwargs
92
  selected_task_id = task_id or self._next_task_id()
 
 
 
93
  self._current_scenario = self._scenarios[selected_task_id]
94
  self._submitted_ranking = []
95
  self._state = ClinicalTrialState(
@@ -130,8 +133,8 @@ class ClinicalTrialEnvironment(
130
  elif action.action_type == "flag_deviation":
131
  self._handle_deviation_flag(action, reward)
132
  elif action.action_type == "rank_patients":
133
- self._handle_ranking(action, reward)
134
- if action.ranking:
135
  done = True
136
  terminal_reason = "ranking_submitted"
137
  elif action.action_type == "submit_decision":
@@ -175,33 +178,44 @@ class ClinicalTrialEnvironment(
175
  """Deterministically compare agent outputs against the current scenario ground truth."""
176
  if self._current_scenario is None:
177
  return DEFAULT_GRADER_SCORE
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  components: List[float] = []
179
- truth = self._current_scenario.ground_truth
180
 
181
  if truth.extracted_fields:
182
  field_hits = sum(
183
  1
184
  for field_name, expected in truth.extracted_fields.items()
185
- if _normalize(self._state.extracted_fields.get(field_name)) == _normalize(expected)
186
  )
187
  score = field_hits / len(truth.extracted_fields)
188
- # Clamp component to ensure it never hits exact 0.0 or 1.0
189
  score = min(max(score, MIN_STRICT_SCORE), MAX_STRICT_SCORE)
190
  components.append(score)
191
 
192
- if self._current_scenario.hidden_exclusions:
193
  exclusion_hits = sum(
194
  1
195
- for exclusion in self._current_scenario.hidden_exclusions
196
- if exclusion in self._state.identified_deviations
197
  )
198
- score = exclusion_hits / len(self._current_scenario.hidden_exclusions)
199
- # Clamp component to ensure it never hits exact 0.0 or 1.0
200
  score = min(max(score, MIN_STRICT_SCORE), MAX_STRICT_SCORE)
201
  components.append(score)
202
 
203
  if truth.ranking:
204
- ranking = self._submitted_ranking
205
  if ranking and len(ranking) == len(truth.ranking):
206
  positional_hits = sum(
207
  1 for actual, expected in zip(ranking, truth.ranking) if actual == expected
@@ -216,14 +230,15 @@ class ClinicalTrialEnvironment(
216
  pairwise_score = pairwise_hits / max(total_pairs, 1)
217
  score = (0.6 * positional_hits) + (0.4 * pairwise_score)
218
  else:
219
- score = MIN_STRICT_SCORE # Penalize missing/incorrect ranking
220
- # Clamp component to ensure it never hits exact 0.0 or 1.0
221
  score = min(max(score, MIN_STRICT_SCORE), MAX_STRICT_SCORE)
222
  components.append(score)
223
 
224
- # Final decision correctness
225
- final_match = _normalize(self._state.final_decision) == _normalize(truth.final_decision)
226
- score = MAX_STRICT_SCORE if final_match else MIN_STRICT_SCORE # Already clamped
 
 
227
  components.append(score)
228
 
229
  if not components:
@@ -235,21 +250,34 @@ class ClinicalTrialEnvironment(
235
 
236
  def grade_easy_screening(self) -> float:
237
  """Task-specific grader for the easy screening task."""
238
- if self._current_scenario is None or self._current_scenario.task_id != "easy":
239
- self.reset(task_id="easy")
240
- return self.grader()
241
 
242
  def grade_medium_ranking(self) -> float:
243
  """Task-specific grader for the medium ranking task."""
244
- if self._current_scenario is None or self._current_scenario.task_id != "medium":
245
- self.reset(task_id="medium")
246
- return self.grader()
247
 
248
  def grade_hard_exclusions(self) -> float:
249
  """Task-specific grader for the hard exclusions task."""
250
- if self._current_scenario is None or self._current_scenario.task_id != "hard":
251
- self.reset(task_id="hard")
252
- return self.grader()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
  def _grade_for_current_task(self) -> float:
255
  """Resolve and run the grader declared by the current scenario."""
@@ -291,6 +319,11 @@ class ClinicalTrialEnvironment(
291
 
292
  def _handle_deviation_flag(self, action: ClinicalTrialAction, reward: ClinicalTrialReward) -> None:
293
  assert self._current_scenario is not None
 
 
 
 
 
294
  submitted = [_normalize(item) for item in action.deviations]
295
  if not submitted:
296
  reward.penalty += HALLUCINATION_PENALTY
@@ -308,8 +341,13 @@ class ClinicalTrialEnvironment(
308
  reward.penalty += HALLUCINATION_PENALTY
309
  reward.notes.append(f"Unsupported deviation claim: {deviation}.")
310
 
311
- def _handle_ranking(self, action: ClinicalTrialAction, reward: ClinicalTrialReward) -> None:
312
  assert self._current_scenario is not None
 
 
 
 
 
313
  ranking = action.ranking
314
  valid_patients = [
315
  patient["patient_id"]
@@ -318,9 +356,10 @@ class ClinicalTrialEnvironment(
318
  if sorted(ranking) != sorted(valid_patients):
319
  reward.penalty += HALLUCINATION_PENALTY
320
  reward.notes.append("Ranking must include each patient exactly once.")
321
- return
322
  self._submitted_ranking = ranking
323
  self._state.final_decision = "ranking_submitted"
 
324
 
325
  def _is_final_submission_correct(self) -> bool:
326
  assert self._current_scenario is not None
 
90
  ) -> ClinicalTrialObservation:
91
  del seed, kwargs
92
  selected_task_id = task_id or self._next_task_id()
93
+ if selected_task_id not in self._scenarios:
94
+ available = ", ".join(sorted(self._scenarios))
95
+ raise ValueError(f"Unknown task_id '{selected_task_id}'. Expected one of: {available}")
96
  self._current_scenario = self._scenarios[selected_task_id]
97
  self._submitted_ranking = []
98
  self._state = ClinicalTrialState(
 
133
  elif action.action_type == "flag_deviation":
134
  self._handle_deviation_flag(action, reward)
135
  elif action.action_type == "rank_patients":
136
+ ranking_accepted = self._handle_ranking(action, reward)
137
+ if ranking_accepted:
138
  done = True
139
  terminal_reason = "ranking_submitted"
140
  elif action.action_type == "submit_decision":
 
178
  """Deterministically compare agent outputs against the current scenario ground truth."""
179
  if self._current_scenario is None:
180
  return DEFAULT_GRADER_SCORE
181
+ return self._score_scenario(
182
+ self._current_scenario,
183
+ self._state,
184
+ self._submitted_ranking,
185
+ )
186
+
187
+ def _score_scenario(
188
+ self,
189
+ scenario: ScenarioSpec,
190
+ state: ClinicalTrialState,
191
+ submitted_ranking: List[str],
192
+ ) -> float:
193
+ """Deterministically compare agent outputs against the provided scenario state."""
194
  components: List[float] = []
195
+ truth = scenario.ground_truth
196
 
197
  if truth.extracted_fields:
198
  field_hits = sum(
199
  1
200
  for field_name, expected in truth.extracted_fields.items()
201
+ if _normalize(state.extracted_fields.get(field_name)) == _normalize(expected)
202
  )
203
  score = field_hits / len(truth.extracted_fields)
 
204
  score = min(max(score, MIN_STRICT_SCORE), MAX_STRICT_SCORE)
205
  components.append(score)
206
 
207
+ if scenario.hidden_exclusions:
208
  exclusion_hits = sum(
209
  1
210
+ for exclusion in scenario.hidden_exclusions
211
+ if exclusion in state.identified_deviations
212
  )
213
+ score = exclusion_hits / len(scenario.hidden_exclusions)
 
214
  score = min(max(score, MIN_STRICT_SCORE), MAX_STRICT_SCORE)
215
  components.append(score)
216
 
217
  if truth.ranking:
218
+ ranking = submitted_ranking
219
  if ranking and len(ranking) == len(truth.ranking):
220
  positional_hits = sum(
221
  1 for actual, expected in zip(ranking, truth.ranking) if actual == expected
 
230
  pairwise_score = pairwise_hits / max(total_pairs, 1)
231
  score = (0.6 * positional_hits) + (0.4 * pairwise_score)
232
  else:
233
+ score = DEFAULT_GRADER_SCORE
 
234
  score = min(max(score, MIN_STRICT_SCORE), MAX_STRICT_SCORE)
235
  components.append(score)
236
 
237
+ if state.final_decision is None:
238
+ score = DEFAULT_GRADER_SCORE
239
+ else:
240
+ final_match = _normalize(state.final_decision) == _normalize(truth.final_decision)
241
+ score = MAX_STRICT_SCORE if final_match else MIN_STRICT_SCORE
242
  components.append(score)
243
 
244
  if not components:
 
250
 
251
  def grade_easy_screening(self) -> float:
252
  """Task-specific grader for the easy screening task."""
253
+ return self._grade_task_by_id("easy")
 
 
254
 
255
  def grade_medium_ranking(self) -> float:
256
  """Task-specific grader for the medium ranking task."""
257
+ return self._grade_task_by_id("medium")
 
 
258
 
259
  def grade_hard_exclusions(self) -> float:
260
  """Task-specific grader for the hard exclusions task."""
261
+ return self._grade_task_by_id("hard")
262
+
263
+ def _grade_task_by_id(self, task_id: str) -> float:
264
+ """Return a task grader score without mutating the environment state."""
265
+ scenario = self._scenarios[task_id]
266
+ if self._current_scenario is not None and self._current_scenario.task_id == task_id:
267
+ state = self._state
268
+ ranking = self._submitted_ranking
269
+ else:
270
+ state = ClinicalTrialState(
271
+ current_task_id=scenario.task_id,
272
+ difficulty=scenario.difficulty,
273
+ title=scenario.title,
274
+ extracted_fields={},
275
+ identified_deviations=[],
276
+ final_decision=None,
277
+ grading_score=DEFAULT_GRADER_SCORE,
278
+ )
279
+ ranking = []
280
+ return self._score_scenario(scenario, state, ranking)
281
 
282
  def _grade_for_current_task(self) -> float:
283
  """Resolve and run the grader declared by the current scenario."""
 
319
 
320
  def _handle_deviation_flag(self, action: ClinicalTrialAction, reward: ClinicalTrialReward) -> None:
321
  assert self._current_scenario is not None
322
+ if self._current_scenario.task_id != "hard":
323
+ reward.penalty += HALLUCINATION_PENALTY
324
+ reward.notes.append("Deviation flagging is only valid for the hard task.")
325
+ return
326
+
327
  submitted = [_normalize(item) for item in action.deviations]
328
  if not submitted:
329
  reward.penalty += HALLUCINATION_PENALTY
 
341
  reward.penalty += HALLUCINATION_PENALTY
342
  reward.notes.append(f"Unsupported deviation claim: {deviation}.")
343
 
344
+ def _handle_ranking(self, action: ClinicalTrialAction, reward: ClinicalTrialReward) -> bool:
345
  assert self._current_scenario is not None
346
+ if self._current_scenario.task_id != "medium":
347
+ reward.penalty += HALLUCINATION_PENALTY
348
+ reward.notes.append("Ranking is only valid for the medium task.")
349
+ return False
350
+
351
  ranking = action.ranking
352
  valid_patients = [
353
  patient["patient_id"]
 
356
  if sorted(ranking) != sorted(valid_patients):
357
  reward.penalty += HALLUCINATION_PENALTY
358
  reward.notes.append("Ranking must include each patient exactly once.")
359
+ return False
360
  self._submitted_ranking = ranking
361
  self._state.final_decision = "ranking_submitted"
362
+ return True
363
 
364
  def _is_final_submission_correct(self) -> bool:
365
  assert self._current_scenario is not None