# Path: misc/numerical.py
# INF = float('inf')


from collections import defaultdict, namedtuple
from heapq import heappush, heappop
from misc.numerical import INF

Pair = namedtuple('Node', ['cost', 'level'])

def compute_costs(state, goal, operators, op=max, unit=False):
    unprocessed = defaultdict(list) # TODO: store this in memory
    unsatisfied = {}
    for operator in operators + [goal]:
        unsatisfied[operator] = len(operator.conditions)
        for literal in operator.conditions:
            unprocessed[literal].append(operator)

    literal_costs = {literal: Pair(0, 0) for literal in unprocessed if literal in state}
    operator_costs = {}
    queue = [(pair.cost, literal) for literal, pair in literal_costs.items()]

    def process_operator(operator):
        operator_cost = operator_level = 0
        if len(operator.conditions) != 0:
            operator_cost = op(literal_costs[literal].cost for literal in operator.conditions)
            operator_level = max(literal_costs[literal].level for literal in operator.conditions)
        operator_costs[operator] = Pair(operator_cost, operator_level)
        if operator == goal:
            # TODO: terminate earlier if the goal is achieved
            return True

# Path: misc/numerical.py
# INF = float('inf')


# Path: strips/hsp.py
from collections import defaultdict, namedtuple
from heapq import heappush, heappop
from misc.numerical import INF


Pair = namedtuple('Node', ['cost', 'level'])

def compute_costs(state, goal, operators, op=max, unit=False):
    unprocessed = defaultdict(list) # TODO: store this in memory
    unsatisfied = {}
    for operator in operators + [goal]:
        unsatisfied[operator] = len(operator.conditions)
        for literal in operator.conditions:
            unprocessed[literal].append(operator)

    literal_costs = {literal: Pair(0, 0) for literal in unprocessed if literal in state}
    operator_costs = {}
    queue = [(pair.cost, literal) for literal, pair in literal_costs.items()]

    def process_operator(operator):
        operator_cost = operator_level = 0
        if len(operator.conditions) != 0:
            operator_cost = op(literal_costs[literal].cost for literal in operator.conditions)
            operator_level = max(literal_costs[literal].level for literal in operator.conditions)
        operator_costs[operator] = Pair(operator_cost, operator_level)
        if operator == goal:
            # TODO: terminate earlier if the goal is achieved
            return True

        literal_cost = operator_cost + (operator.cost if not unit else 1)