Spaces:
Sleeping
Sleeping
Download src/memory/world_model_evaluation.py from ThomasHeisig/MHRN-Space: direct link, hf CLI and curl.
- Browser
- Download file 5.48 kB
-
https://huggingface.co/spaces/ThomasHeisig/MHRN-Space/resolve/main/src/memory/world_model_evaluation.py
- Command line
-
hf download hf://spaces/ThomasHeisig/MHRN-Space/src/memory/world_model_evaluation.py
-
curl -L -o world_model_evaluation.py https://huggingface.co/spaces/ThomasHeisig/MHRN-Space/resolve/main/src/memory/world_model_evaluation.py
5.48 kB
| """Offline decision-benefit evaluation for Stage-6 world-model experiments. | |
| The evaluator scores frozen multistep rollouts under matched candidate horizons. | |
| It never dispatches actions and is not an actuation authority. Recommendations are | |
| research outputs only and must not be interpreted as evidence of planning unless a | |
| registered behavioural experiment supports that claim. | |
| """ | |
| from __future__ import annotations | |
| import copy | |
| import math | |
| from collections.abc import Callable, Sequence | |
| from dataclasses import dataclass | |
| from typing import Any | |
| from .multistep_world_model import ( | |
| ActionConditionedWorldModel, | |
| RolloutResult, | |
| StateAction, | |
| ) | |
| class WorldModelEvaluationError(ValueError): | |
| """Raised when an offline decision-benefit evaluation is invalid.""" | |
| class ActionSequenceCandidate: | |
| """Named, fixed-horizon action sequence evaluated without actuation.""" | |
| label: str | |
| actions: tuple[StateAction, ...] | |
| def __post_init__(self) -> None: | |
| if not self.label.strip(): | |
| raise WorldModelEvaluationError("candidate label must be non-empty") | |
| if not self.actions: | |
| raise WorldModelEvaluationError("candidate actions must be non-empty") | |
| class CandidateEvaluation: | |
| """Read-only evaluation result for one action-sequence candidate.""" | |
| label: str | |
| rollout: RolloutResult | |
| eligible: bool | |
| score: float | None | |
| reason: str | |
| class DecisionRecommendation: | |
| """Offline recommendation; never an actuator command or safety authorization.""" | |
| selected_label: str | None | |
| evaluations: tuple[CandidateEvaluation, ...] | |
| scientific_status: str = "offline_reference_evaluator_not_actuation_authority" | |
| TrajectoryScorer = Callable[[RolloutResult], float] | |
| def _eligible_sort_key(item: CandidateEvaluation) -> tuple[float, str]: | |
| if item.score is None: | |
| raise WorldModelEvaluationError("eligible candidate is missing a score") | |
| return (-item.score, item.label) | |
| class OfflineDecisionEvaluator: | |
| """Compare matched candidate rollouts without mutating or actuating the model.""" | |
| scientific_status = "offline_reference_evaluator_not_actuation_authority" | |
| def __init__( | |
| self, | |
| model: ActionConditionedWorldModel, | |
| scorer: TrajectoryScorer, | |
| *, | |
| max_steps: int = 32, | |
| ) -> None: | |
| if type(max_steps) is not int or max_steps <= 0: | |
| raise WorldModelEvaluationError("max_steps must be a positive integer") | |
| self.model = model | |
| self.scorer = scorer | |
| self.max_steps = max_steps | |
| def evaluate( | |
| self, | |
| initial_state: dict[str, Any], | |
| candidates: Sequence[ActionSequenceCandidate], | |
| ) -> DecisionRecommendation: | |
| """Score complete known rollouts under equal horizons and deterministic ties.""" | |
| if not candidates: | |
| raise WorldModelEvaluationError("at least one candidate is required") | |
| labels = [candidate.label for candidate in candidates] | |
| if len(labels) != len(set(labels)): | |
| raise WorldModelEvaluationError("candidate labels must be unique") | |
| horizons = {len(candidate.actions) for candidate in candidates} | |
| if len(horizons) != 1: | |
| raise WorldModelEvaluationError("candidate horizons must be matched") | |
| horizon = next(iter(horizons)) | |
| if horizon > self.max_steps: | |
| raise WorldModelEvaluationError( | |
| "candidate horizon exceeds evaluation budget" | |
| ) | |
| before = copy.deepcopy(self.model.state_dict()) | |
| evaluations: list[CandidateEvaluation] = [] | |
| for candidate in candidates: | |
| rollout = self.model.rollout( | |
| initial_state, | |
| candidate.actions, | |
| max_steps=self.max_steps, | |
| ) | |
| if rollout.terminated_early or rollout.final_state is None: | |
| evaluations.append( | |
| CandidateEvaluation( | |
| label=candidate.label, | |
| rollout=rollout, | |
| eligible=False, | |
| score=None, | |
| reason="unknown_transition", | |
| ) | |
| ) | |
| continue | |
| score = self.scorer(rollout) | |
| if isinstance(score, bool) or not math.isfinite(score): | |
| raise WorldModelEvaluationError("trajectory score must be finite") | |
| evaluations.append( | |
| CandidateEvaluation( | |
| label=candidate.label, | |
| rollout=rollout, | |
| eligible=True, | |
| score=float(score), | |
| reason="complete_rollout", | |
| ) | |
| ) | |
| if self.model.state_dict() != before: | |
| raise WorldModelEvaluationError( | |
| "offline evaluation mutated the world model" | |
| ) | |
| eligible = [ | |
| item for item in evaluations if item.eligible and item.score is not None | |
| ] | |
| eligible.sort(key=_eligible_sort_key) | |
| selected = eligible[0].label if eligible else None | |
| return DecisionRecommendation(selected, tuple(evaluations)) | |
| __all__ = [ | |
| "ActionSequenceCandidate", | |
| "CandidateEvaluation", | |
| "DecisionRecommendation", | |
| "OfflineDecisionEvaluator", | |
| "TrajectoryScorer", | |
| "WorldModelEvaluationError", | |
| ] | |