# Path: planner/operators.py
# def derive_predicates(state, axioms):
#   if not axioms:
#     return state, []
#   is_strips = 'strips' in axioms[0].__class__.__module__ # TODO: clean this up
#   if is_strips:
#     from strips.operators import derive_state
#     return derive_state(state, axioms)
#   return derive_predicates_slow(state, axioms)
# 
# class MacroOperator(object):
#   def __init__(self, *operators):
#     self.operators = tuple(operators)
#     self.cost = sum(operator.cost for operator in operators)
#   def __contains__(self, state):
#     return self(state) is not None
#   def __call__(self, state):
#     states = [state]
#     for operator in self.operators:
#       new_state = operator(states[-1])
#       if new_state is None: return None
#       states.append(new_state)
#     return states
#   def __iter__(self):
#     return (operator for operator in self.operators)
#   def __len__(self):
#     return len(self.operators)
#   def __eq__(self, other):
#     if type(self) != type(other): return False
#     return self.operators == other.operators
#   def __ne__(self, other):
#     return not self == other
#   def __hash__(self):
#     return hash((self.__class__, self.operators))
#   def __str__(self):
#     return self.__class__.__name__ + str_object(self.operators)
#   __repr__ = __str__
# 
# Path: misc/functions.py
# def elapsed_time(start_time):
#   return time.time() - start_time
# 
# def safe_remove(sequence, item):
#   try:
#     sequence.remove(item)
#     return True
#   except ValueError:
#     return False
# 
# def implies(a, b):
#   return not a or b
# 
# Path: misc/numerical.py
# INF = float('inf')
# 
# Path: misc/objects.py
# def str_line(*args):
#   return ''.join(str_object(item) for item in args)


from collections import namedtuple
from .operators import derive_predicates, MacroOperator
from misc.functions import elapsed_time, safe_remove, implies
from misc.numerical import INF
from misc.objects import str_line
import time
        self.best_h = None # None | INF
    def has_state(self, state):
        return state in self.vertices
    __contains__ = has_state
    def get_state(self, state):
        if state not in self:
            self.vertices[state] = Vertex(state, self)
        return self.vertices[state]
    __getitem__ = get_state
    def __iter__(self):
        return iter(self.vertices.values())
    def __len__(self):
        return len(self.vertices)
    def new_iteration(self, vertex):
        self.iterations += 1
        if elapsed_time(self.last_dump) >= self.dump_rate:
            self.dump()
        # TODO: record dead ends here
        #return vertex.is_dead_end() # TODO: might not have called h_cost
    def is_active(self):
        return (elapsed_time(self.start_time) < self.max_time) or (self.iterations < self.max_iterations)
    def extend(self, vertex, operator):
        if (vertex.cost + operator.cost <= self.max_cost) \
                and (vertex.length + len(operator) <= self.max_length) \
                and vertex.contained(operator):
            #if vertex.state in operator:
            if self.axioms:
                assert not isinstance(operator, MacroOperator)
                sink_state = operator.apply(vertex.state) # TODO - this won't work for MacroOperators yet?
            else:

# Path: planner/operators.py
# def derive_predicates(state, axioms):
#   if not axioms:
#     return state, []
#   is_strips = 'strips' in axioms[0].__class__.__module__ # TODO: clean this up
#   if is_strips:
#     from strips.operators import derive_state
#     return derive_state(state, axioms)
#   return derive_predicates_slow(state, axioms)
# 
# class MacroOperator(object):
#   def __init__(self, *operators):
#     self.operators = tuple(operators)
#     self.cost = sum(operator.cost for operator in operators)
#   def __contains__(self, state):
#     return self(state) is not None
#   def __call__(self, state):
#     states = [state]
#     for operator in self.operators:
#       new_state = operator(states[-1])
#       if new_state is None: return None
#       states.append(new_state)
#     return states
#   def __iter__(self):
#     return (operator for operator in self.operators)
#   def __len__(self):
#     return len(self.operators)
#   def __eq__(self, other):
#     if type(self) != type(other): return False
#     return self.operators == other.operators
#   def __ne__(self, other):
#     return not self == other
#   def __hash__(self):
#     return hash((self.__class__, self.operators))
#   def __str__(self):
#     return self.__class__.__name__ + str_object(self.operators)
#   __repr__ = __str__
# 
# Path: misc/functions.py
# def elapsed_time(start_time):
#   return time.time() - start_time
# 
# def safe_remove(sequence, item):
#   try:
#     sequence.remove(item)
#     return True
#   except ValueError:
#     return False
# 
# def implies(a, b):
#   return not a or b
# 
# Path: misc/numerical.py
# INF = float('inf')
# 
# Path: misc/objects.py
# def str_line(*args):
#   return ''.join(str_object(item) for item in args)


# Path: planner/state_space.py
from collections import namedtuple
from .operators import derive_predicates, MacroOperator
from misc.functions import elapsed_time, safe_remove, implies
from misc.numerical import INF
from misc.objects import str_line
import time

        self.best_h = None # None | INF
    def has_state(self, state):
        return state in self.vertices
    __contains__ = has_state
    def get_state(self, state):
        if state not in self:
            self.vertices[state] = Vertex(state, self)
        return self.vertices[state]
    __getitem__ = get_state
    def __iter__(self):
        return iter(self.vertices.values())
    def __len__(self):
        return len(self.vertices)
    def new_iteration(self, vertex):
        self.iterations += 1
        if elapsed_time(self.last_dump) >= self.dump_rate:
            self.dump()
        # TODO: record dead ends here
        #return vertex.is_dead_end() # TODO: might not have called h_cost
    def is_active(self):
        return (elapsed_time(self.start_time) < self.max_time) or (self.iterations < self.max_iterations)
    def extend(self, vertex, operator):
        if (vertex.cost + operator.cost <= self.max_cost) \
                and (vertex.length + len(operator) <= self.max_length) \
                and vertex.contained(operator):
            #if vertex.state in operator:
            if self.axioms:
                assert not isinstance(operator, MacroOperator)
                sink_state = operator.apply(vertex.state) # TODO - this won't work for MacroOperators yet?
            else:

                sink_state = operator(vertex.state)[-1] if isinstance(operator, MacroOperator) else operator(vertex.state)