def compute_icm_intrinsic_reward(self, states: Tensor, actions: Tensor, next_states: Tensor) -> Tensor:
        """
        **Overview**:
            Given the current state, action, and next state, this function computes the ICM intrinsic reward
            based on the prediction error of the ICM model.
        Arguments:
            - states (:obj:`Tensor`): The input state tensor.
            - actions (:obj:`Tensor`): The input action tensor.
            - next_states (:obj:`Tensor`): The input next state tensor.
        Returns:
            - icm_reward (:obj:`Tensor`): The ICM intrinsic reward.
        """
        # Compute the real next state feature, the predicted next state feature, and the predicted action.
        real_next_state_feature, pred_next_state_feature, _ = self.forward(states, next_states, actions)
        # Compute the prediction error as the MSE loss between the real and predicted next state features.
        raw_icm_reward = self.forward_mse(real_next_state_feature, pred_next_state_feature).mean(dim=1)
        # Normalize the raw ICM reward to the [0, 1] range.
        icm_reward = (raw_icm_reward - raw_icm_reward.min()) / (raw_icm_reward.max() - raw_icm_reward.min() + 1e-8)
        # Return the normalized ICM reward.
        return icm_reward

        **Overview**:
            Given the current state, action, and next state, this function computes the ICM intrinsic reward
            based on the prediction error of the ICM model.
        Arguments:
            - states (:obj:`Tensor`): The input state tensor.
            - actions (:obj:`Tensor`): The input action tensor.
            - next_states (:obj:`Tensor`): The input next state tensor.
        Returns:
            - icm_reward (:obj:`Tensor`): The ICM intrinsic reward.
        
chapter4_reward/curiosity_icm.py