code: def next_state_reward_dist(
      self, state: State, action: Action
  ) -> StateDistribution:
      probs = [self.noise_prob] * len(self.action_space)
      assert isinstance(
          action.value, int
      ), f"got type {type(action.value)} instead of int"
      # pyre-fixme[16]: `int` has no attribute `__setitem__`.
      probs[action.value] = 1 - self.epsilon
      states = {}
      for a in self.action_space:
          sr = self._gridworld._next_state_reward(state, a)
          if sr.state in states:
              rp = states[sr.state]
              states[sr.state] = RewardProbability(
                  rp.reward + sr.reward,
                  # pyre-fixme[16]: `int` has no attribute `__getitem__`.
                  rp.prob + probs[a.value],
              )
          else:
              states[sr.state] = RewardProbability(
                  sr.reward, probs[a.value]
              )
      return states
  
imports: import logging
  import random
  from typing import Iterable, Optional, Sequence, Tuple
  import numpy
  import torch
  from reagent.ope.estimators.sequential_estimators import DMEstimator, DoublyRobustEstimator, EpsilonGreedyRLPolicy, IPSEstimator, MAGICEstimator, NeuralDualDICE, RewardProbability, RLEstimatorInput, State, StateDistribution, StateReward, ValueFunction
  from reagent.ope.estimators.types import Action, ActionSpace
  from reagent.ope.test.envs import Environment, PolicyLogGenerator
  from reagent.ope.trainers.rl_tabular_trainers import DPTrainer, DPValueFunction, EstimatedStateValueFunction, TabularPolicy
label_desc: Use image node_id 4 for calling the NoiseGridWorldModel obj's underlying member method code with example usage: obj.next_state_reward_dist(state, action) and returns: states