You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
4.2 KiB

  1. from enum import Enum
  2. import stormpy.core
  3. class SimulatorObservationMode(Enum):
  4. STATE_LEVEL = 0,
  5. PROGRAM_LEVEL = 1
  6. class SimulatorActionMode(Enum):
  7. INDEX_LEVEL = 0
  8. class Simulator:
  9. """
  10. Base class for simulators.
  11. """
  12. def __init__(self, seed=None):
  13. self._seed = seed
  14. self._observation_mode = SimulatorObservationMode.STATE_LEVEL
  15. self._action_mode = SimulatorActionMode.INDEX_LEVEL
  16. def available_actions(self):
  17. """
  18. Returns an iterable over the available actions. The action mode may be used to select how actions are referred to.
  19. TODO: Support multiple action modes
  20. :return:
  21. """
  22. raise NotImplementedError("Abstract Superclass")
  23. def step(self, action=None):
  24. """
  25. Do a step taking the passed action.
  26. :param action: The index of the action, for deterministic actions, action may be None.
  27. :return: The observation (on state or program level).
  28. """
  29. raise NotImplementedError("Abstract superclass")
  30. def restart(self):
  31. """
  32. Reset the simulator to the initial state
  33. """
  34. raise NotImplementedError("Abstract superclass")
  35. def is_done(self):
  36. """
  37. Is the simulator in a sink state?
  38. :return: Yes, if the simulator is in a sink state.
  39. """
  40. return False
  41. def set_observation_mode(self, mode):
  42. """
  43. :param mode: STATE_LEVEL or PROGRAM_LEVEL
  44. :type mode:
  45. """
  46. if not isinstance(mode, SimulatorObservationMode):
  47. raise RuntimeError("Observation mode must be a SimulatorObservationMode")
  48. self._observation_mode = mode
  49. class SparseSimulator(Simulator):
  50. """
  51. Simulator on top of sparse models.
  52. """
  53. def __init__(self, model, seed=None):
  54. super().__init__(seed)
  55. self._model = model
  56. self._engine = stormpy.core._DiscreteTimeSparseModelSimulatorDouble(model)
  57. if seed is not None:
  58. self._engine.set_seed(seed)
  59. self._state_valuations = None
  60. def available_actions(self):
  61. return range(self.nr_available_actions())
  62. def nr_available_actions(self):
  63. return self._model.get_nr_available_actions(self._engine.get_current_state())
  64. def _report_observation(self):
  65. if self._observation_mode == SimulatorObservationMode.STATE_LEVEL:
  66. return self._engine.get_current_state()
  67. elif self._observation_mode == SimulatorObservationMode.PROGRAM_LEVEL:
  68. return self._state_valuations.get_state(self._engine.get_current_state())
  69. def step(self, action=None):
  70. if action is None:
  71. if self._model.is_nondeterministic_model and self.nr_available_actions() > 1:
  72. raise RuntimeError("Must specify an action in nondeterministic models.")
  73. check = self._engine.step(0)
  74. assert check
  75. else:
  76. if action >= self.nr_available_actions():
  77. raise RuntimeError(f"Only {self.nr_available_actions()} actions available")
  78. check = self._engine.step(action)
  79. assert check
  80. return self._report_observation()
  81. def restart(self):
  82. self._engine.reset_to_initial_state()
  83. return self._report_observation()
  84. def is_done(self):
  85. return self._model.is_sink_state(self._engine.get_current_state())
  86. def set_observation_mode(self, mode):
  87. super().set_observation_mode(mode)
  88. if self._observation_mode == SimulatorObservationMode.PROGRAM_LEVEL:
  89. if not self._model.has_state_valuations():
  90. raise RuntimeError("Program level observations require model with state valuations")
  91. self._state_valuations = self._model.state_valuations
  92. def create_simulator(model, seed = None):
  93. """
  94. Factory method for creating a simulator.
  95. :param model: Some form of model
  96. :param seed: A seed for reproducibility. If None (default), the seed is internally generated.
  97. :return: A simulator that can simulate on top of this model
  98. """
  99. if isinstance(model, stormpy.storage._ModelBase):
  100. if model.is_sparse_model:
  101. return SparseSimulator(model, seed)
  102. else:
  103. raise NotImplementedError("Currently, we only support simulators for sparse models.")