# 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
                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)
            if (sink_state is not None) and (self[sink_state].extensions < self.max_extensions):
                sink_vertex = self[sink_state]
                self.edges.append(Edge(vertex, sink_vertex, operator, self))
                sink_vertex.extensions += 1
                return sink_vertex
        return None
    def retrace(self, vertex):
        if vertex is not None:
            if vertex == self.root:
                return []
            sequence = self.retrace(vertex.parent_edge.source)
            if sequence is not None:
                return sequence + list(vertex.parent_edge.operator)
        return None
    def plan(self, vertex):
        sequence = self.retrace(vertex)
        if sequence is None:
            return None
        return Plan(self.root.state, sequence)
    def solution(self, vertex):
        #self.dump()
        return Solution(self.plan(vertex), self)
    def failure(self):
        self.dump()
        return Solution(None, self)
    def time_elapsed(self):

# 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

                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)
            if (sink_state is not None) and (self[sink_state].extensions < self.max_extensions):
                sink_vertex = self[sink_state]
                self.edges.append(Edge(vertex, sink_vertex, operator, self))
                sink_vertex.extensions += 1
                return sink_vertex
        return None
    def retrace(self, vertex):
        if vertex is not None:
            if vertex == self.root:
                return []
            sequence = self.retrace(vertex.parent_edge.source)
            if sequence is not None:
                return sequence + list(vertex.parent_edge.operator)
        return None
    def plan(self, vertex):
        sequence = self.retrace(vertex)
        if sequence is None:
            return None
        return Plan(self.root.state, sequence)
    def solution(self, vertex):
        #self.dump()
        return Solution(self.plan(vertex), self)
    def failure(self):
        self.dump()
        return Solution(None, self)
    def time_elapsed(self):

        return elapsed_time(self.start_time)