# Path: mdpproblog/fluent.py
# class Fluent(object):
#     """
#     Factory class for building fluent terms. A fluent term is a
#     problog.logic.Term with a problog.logic.Constant as last argument
#     representing its timestep.
#     """
# 
#     @classmethod
#     def create_fluent(cls, term, timestep):
#         """"
#         Return a new fluent made from `term` with given `timestep`.
# 
#         :param term: any problog term
#         :type term: problog.logic.Term
#         :param timestep: timestep numeric value
#         :type timestep: int
#         :rtype: problog.logic.Term
#         """
#         args = term.args + (Constant(timestep),)
#         return term.with_args(*args)
# 
# class StateSpace(object):
#     """
#     Iterator class for looping over vector representations of
#     states in a factored MDP defined by `state_fluents`. Each state
#     is implemented by an OrderedDict of (problog.logic.Term, 0/1).
# 
#     :param state_fluents: predicates defining a state in a given timestep
#     :type state_fluents: list of problog.logic.Term
#     """
# 
#     def __init__(self, state_fluents):
#         self.__state_fluents = state_fluents
#         self.__state_space_size = 2**len(self.__state_fluents)
# 
#     def __len__(self):
#         """ Return the number of states of the state space. """
#         return self.__state_space_size
# 
#     def __iter__(self):
#         """ Return an iterator over the state space. """
#         self.__state_number = 0
#         self.__state = OrderedDict([ (fluent, 1) for fluent in self.__state_fluents ])
#         return self
# 
#     def __next__(self):
#         """ Return representation of next state in the sequence. """
#         if self.__state_number == self.__state_space_size:
#             raise StopIteration
# 
#         for fluent, value in self.__state.items():
#             if value == 1:
#                 self.__state[fluent] = 0
#             else:
#                 self.__state[fluent] = 1
#                 break
# 
#         self.__state_number += 1
#         return self.__state
# 
#     def __getitem__(self, index):
#         """
#         Return the state representation with given `index`.
# 
#         :param index: state index in state space
#         :type index: int
#         """
#         state = []
#         for fluent in self.__state_fluents:
#             value = index % 2
#             index //= 2
#             state.append((fluent, value))
#         return tuple(state)
# 
#     @classmethod
#     def state(cls, valuation):
#         """
#         Return the state representation of a `valuation` of fluents.
# 
#         :param valuation: mapping from fluent to boolean value
#         :type valuation: list of pairs (Fluent, bool)
#         :rtype: OrderedDict
#         """
#         return OrderedDict(valuation)
# 
#     @classmethod
#     def index(cls, state):
#         """
#         Return the `state` index in the state space.
# 
#         :param state: state representation
#         :type state: OrderedDict
#         :rtype: int
#         """
#         i = 0
#         index = 0
#         for _, value in state.items():
#             index += value * 2 ** i
#             i += 1
#         return index
# 
# class ActionSpace(object):
#     """
#     Iterator class for looping over vector representations of
#     `actions` in a factored MDP. Each action is implemented by
#     an OrderedDict of (problog.logic.Term, 0/1).
# 
#     :param actions: predicates listing possible actions
#     :type actions: list of problog.logic.Term
#     """
# 
#     def __init__(self, actions):
#         self.__actions = actions
#         self.__action_space_size = len(self.__actions)
# 
#     def __len__(self):
#         """ Return the number of actions of the action space. """
#         return self.__action_space_size
# 
#     def __iter__(self):
#         """ Return an iterator over the action space. """
#         self.__action_number = 0
#         self.__action = OrderedDict([ (action, 0) for action in self.__actions ])
#         self.__action[self.__actions[-1]] = 1
#         return self
# 
#     def __next__(self):
#         """ Return representation of next action in the sequence. """
#         if self.__action_number == self.__action_space_size:
#             raise StopIteration
# 
#         self.__action[self.__actions[self.__action_number - 1]] = 0
#         self.__action[self.__actions[self.__action_number]] = 1
# 
#         self.__action_number += 1
#         return self.__action
# 
#     def __getitem__(self, index):
#         """
#         Return the action representation with given `index`.
# 
#         :param index: action index in action space
#         :type index: int
#         """
#         return self.__actions[index]
# 
#     @classmethod
#     def index(cls, action):
#         """
#         Return action index in the action space.
# 
#         :param action: action representation
#         :type action: OrderedDict
#         :rtype: int
#         """
#         for index, fluent in enumerate(action):
#             if action[fluent] == 1:
#                 return index


import mdpproblog.engine as eng
from mdpproblog.fluent import Fluent, StateSpace, ActionSpace
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with MDP-ProbLog.  If not, see <http://www.gnu.org/licenses/>.



class MDP(object):
    """
    Representation of an MDP and its components. Implemented as a bridge
    class to the ProbLog programs specifying the MDP domain and problems.

    :param model: a valid MDP-ProbLog program
    :type model: str
    """

    def __init__(self, model):
        self._model = model
        self._engine = eng.Engine(model)

        self.__transition_cache = {}
        self.__reward_cache = {}

        self.__prepare()

    def __prepare(self):
        """ Prepare the mdp-problog knowledge database to accept queries. """

        # add dummy current state fluents probabilistic facts
        for term in self.state_fluents():

# Path: mdpproblog/fluent.py
# class Fluent(object):
#     """
#     Factory class for building fluent terms. A fluent term is a
#     problog.logic.Term with a problog.logic.Constant as last argument
#     representing its timestep.
#     """
# 
#     @classmethod
#     def create_fluent(cls, term, timestep):
#         """"
#         Return a new fluent made from `term` with given `timestep`.
# 
#         :param term: any problog term
#         :type term: problog.logic.Term
#         :param timestep: timestep numeric value
#         :type timestep: int
#         :rtype: problog.logic.Term
#         """
#         args = term.args + (Constant(timestep),)
#         return term.with_args(*args)
# 
# class StateSpace(object):
#     """
#     Iterator class for looping over vector representations of
#     states in a factored MDP defined by `state_fluents`. Each state
#     is implemented by an OrderedDict of (problog.logic.Term, 0/1).
# 
#     :param state_fluents: predicates defining a state in a given timestep
#     :type state_fluents: list of problog.logic.Term
#     """
# 
#     def __init__(self, state_fluents):
#         self.__state_fluents = state_fluents
#         self.__state_space_size = 2**len(self.__state_fluents)
# 
#     def __len__(self):
#         """ Return the number of states of the state space. """
#         return self.__state_space_size
# 
#     def __iter__(self):
#         """ Return an iterator over the state space. """
#         self.__state_number = 0
#         self.__state = OrderedDict([ (fluent, 1) for fluent in self.__state_fluents ])
#         return self
# 
#     def __next__(self):
#         """ Return representation of next state in the sequence. """
#         if self.__state_number == self.__state_space_size:
#             raise StopIteration
# 
#         for fluent, value in self.__state.items():
#             if value == 1:
#                 self.__state[fluent] = 0
#             else:
#                 self.__state[fluent] = 1
#                 break
# 
#         self.__state_number += 1
#         return self.__state
# 
#     def __getitem__(self, index):
#         """
#         Return the state representation with given `index`.
# 
#         :param index: state index in state space
#         :type index: int
#         """
#         state = []
#         for fluent in self.__state_fluents:
#             value = index % 2
#             index //= 2
#             state.append((fluent, value))
#         return tuple(state)
# 
#     @classmethod
#     def state(cls, valuation):
#         """
#         Return the state representation of a `valuation` of fluents.
# 
#         :param valuation: mapping from fluent to boolean value
#         :type valuation: list of pairs (Fluent, bool)
#         :rtype: OrderedDict
#         """
#         return OrderedDict(valuation)
# 
#     @classmethod
#     def index(cls, state):
#         """
#         Return the `state` index in the state space.
# 
#         :param state: state representation
#         :type state: OrderedDict
#         :rtype: int
#         """
#         i = 0
#         index = 0
#         for _, value in state.items():
#             index += value * 2 ** i
#             i += 1
#         return index
# 
# class ActionSpace(object):
#     """
#     Iterator class for looping over vector representations of
#     `actions` in a factored MDP. Each action is implemented by
#     an OrderedDict of (problog.logic.Term, 0/1).
# 
#     :param actions: predicates listing possible actions
#     :type actions: list of problog.logic.Term
#     """
# 
#     def __init__(self, actions):
#         self.__actions = actions
#         self.__action_space_size = len(self.__actions)
# 
#     def __len__(self):
#         """ Return the number of actions of the action space. """
#         return self.__action_space_size
# 
#     def __iter__(self):
#         """ Return an iterator over the action space. """
#         self.__action_number = 0
#         self.__action = OrderedDict([ (action, 0) for action in self.__actions ])
#         self.__action[self.__actions[-1]] = 1
#         return self
# 
#     def __next__(self):
#         """ Return representation of next action in the sequence. """
#         if self.__action_number == self.__action_space_size:
#             raise StopIteration
# 
#         self.__action[self.__actions[self.__action_number - 1]] = 0
#         self.__action[self.__actions[self.__action_number]] = 1
# 
#         self.__action_number += 1
#         return self.__action
# 
#     def __getitem__(self, index):
#         """
#         Return the action representation with given `index`.
# 
#         :param index: action index in action space
#         :type index: int
#         """
#         return self.__actions[index]
# 
#     @classmethod
#     def index(cls, action):
#         """
#         Return action index in the action space.
# 
#         :param action: action representation
#         :type action: OrderedDict
#         :rtype: int
#         """
#         for index, fluent in enumerate(action):
#             if action[fluent] == 1:
#                 return index


# Path: mdpproblog/mdp.py
import mdpproblog.engine as eng
from mdpproblog.fluent import Fluent, StateSpace, ActionSpace

# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with MDP-ProbLog.  If not, see <http://www.gnu.org/licenses/>.



class MDP(object):
    """
    Representation of an MDP and its components. Implemented as a bridge
    class to the ProbLog programs specifying the MDP domain and problems.

    :param model: a valid MDP-ProbLog program
    :type model: str
    """

    def __init__(self, model):
        self._model = model
        self._engine = eng.Engine(model)

        self.__transition_cache = {}
        self.__reward_cache = {}

        self.__prepare()

    def __prepare(self):
        """ Prepare the mdp-problog knowledge database to accept queries. """

        # add dummy current state fluents probabilistic facts
        for term in self.state_fluents():

            self._engine.add_fact(Fluent.create_fluent(term, 0), 0.5)