def __search(sync_net, ini, fin, cost_function, skip, ret_tuple_as_trans_desc=False, max_align_time_trace=sys.maxsize): start_time = time.time() decorate_transitions_prepostset(sync_net) decorate_places_preset_trans(sync_net) incidence_matrix = inc_mat_construct(sync_net) ini_vec, fin_vec, cost_vec = utils.__vectorize_initial_final_cost( incidence_matrix, ini, fin, cost_function) closed = set() a_matrix = np.asmatrix(incidence_matrix.a_matrix).astype(np.float64) g_matrix = -np.eye(len(sync_net.transitions)) h_cvx = np.matrix(np.zeros(len(sync_net.transitions))).transpose() cost_vec = [x * 1.0 for x in cost_vec] use_cvxopt = False if lp_solver.DEFAULT_LP_SOLVER_VARIANT == lp_solver.CVXOPT_SOLVER_CUSTOM_ALIGN or lp_solver.DEFAULT_LP_SOLVER_VARIANT == lp_solver.CVXOPT_SOLVER_CUSTOM_ALIGN_ILP: use_cvxopt = True if use_cvxopt: # not available in the latest version of PM4Py from cvxopt import matrix a_matrix = matrix(a_matrix) g_matrix = matrix(g_matrix) h_cvx = matrix(h_cvx) cost_vec = matrix(cost_vec) h, x = utils.__compute_exact_heuristic_new_version( sync_net, a_matrix, h_cvx, g_matrix, cost_vec, incidence_matrix, ini, fin_vec, lp_solver.DEFAULT_LP_SOLVER_VARIANT, use_cvxopt=use_cvxopt) ini_state = utils.SearchTuple(0 + h, 0, h, ini, None, None, x, True) open_set = [ini_state] heapq.heapify(open_set) visited = 0 queued = 0 traversed = 0 lp_solved = 1 trans_empty_preset = set(t for t in sync_net.transitions if len(t.in_arcs) == 0) while not len(open_set) == 0: if (time.time() - start_time) > max_align_time_trace: return None curr = heapq.heappop(open_set) current_marking = curr.m while not curr.trust: if (time.time() - start_time) > max_align_time_trace: return None already_closed = current_marking in closed if already_closed: curr = heapq.heappop(open_set) current_marking = curr.m continue h, x = utils.__compute_exact_heuristic_new_version( sync_net, a_matrix, h_cvx, g_matrix, cost_vec, incidence_matrix, curr.m, fin_vec, lp_solver.DEFAULT_LP_SOLVER_VARIANT, use_cvxopt=use_cvxopt) lp_solved += 1 # 11/10/19: shall not a state for which we compute the exact heuristics be # by nature a trusted solution? tp = utils.SearchTuple(curr.g + h, curr.g, h, curr.m, curr.p, curr.t, x, True) # 11/10/2019 (optimization ZA) heappushpop is slightly more efficient than pushing # and popping separately curr = heapq.heappushpop(open_set, tp) current_marking = curr.m # max allowed heuristics value (27/10/2019, due to the numerical instability of some of our solvers) if curr.h > lp_solver.MAX_ALLOWED_HEURISTICS: continue # 12/10/2019: do it again, since the marking could be changed already_closed = current_marking in closed if already_closed: continue # 12/10/2019: the current marking can be equal to the final marking only if the heuristics # (underestimation of the remaining cost) is 0. Low-hanging fruits if curr.h < 0.01: if current_marking == fin: return utils.__reconstruct_alignment( curr, visited, queued, traversed, ret_tuple_as_trans_desc=ret_tuple_as_trans_desc, lp_solved=lp_solved) closed.add(current_marking) visited += 1 possible_enabling_transitions = copy(trans_empty_preset) for p in current_marking: for t in p.ass_trans: possible_enabling_transitions.add(t) enabled_trans = [ t for t in possible_enabling_transitions if t.sub_marking <= current_marking ] trans_to_visit_with_cost = [ (t, cost_function[t]) for t in enabled_trans if not (t is not None and utils.__is_log_move(t, skip) and utils.__is_model_move(t, skip)) ] for t, cost in trans_to_visit_with_cost: traversed += 1 new_marking = utils.add_markings(current_marking, t.add_marking) if new_marking in closed: continue g = curr.g + cost queued += 1 h, x = utils.__derive_heuristic(incidence_matrix, cost_vec, curr.x, t, curr.h) trustable = utils.__trust_solution(x) new_f = g + h tp = utils.SearchTuple(new_f, g, h, new_marking, curr, t, x, trustable) heapq.heappush(open_set, tp)
def __align(model_struct, trace_struct, product_net, corresp, sync_cost=align_utils.STD_SYNC_COST, max_align_time_trace=sys.maxsize, ret_tuple_as_trans_desc=False): """ Alignments using Dijkstra Parameters --------------- model_struct Efficient model structure trace_struct Efficient trace structure product_net Synchronous product net sync_cost Cost of a sync move (limitation: all sync moves shall have the same cost in this setting) corresp Correspondence between indexed places and places of the sync product net max_align_time_trace Maximum alignment time for a trace (in seconds) ret_tuple_as_trans_desc Says if the alignments shall be constructed including also the name of the transition, or only the label (default=False includes only the label) Returns -------------- alignment Alignment of the trace, including: alignment: the sequence of moves queued: the number of states that have been queued visited: the number of states that have been visited cost: the cost of the alignment """ start_time = time.time() trans_pre_dict = model_struct[TRANS_PRE_DICT] trans_post_dict = model_struct[TRANS_POST_DICT] trans_labels_dict = model_struct[TRANS_LABELS_DICT] transf_model_cost_function = model_struct[TRANSF_MODEL_COST_FUNCTION] transf_trace = trace_struct[TRANSF_TRACE] trace_cost_function = trace_struct[TRACE_COST_FUNCTION] sync_net, ini, fin, cost_function = product_net incidence_matrix = construct(sync_net) ini_vec, fin_vec, cost_vec = utils.__vectorize_initial_final_cost( incidence_matrix, ini, fin, cost_function) a_matrix = np.asmatrix(incidence_matrix.a_matrix).astype(np.float64) g_matrix = -np.eye(len(sync_net.transitions)) h_cvx = np.matrix(np.zeros(len(sync_net.transitions))).transpose() cost_vec = [x * 1.0 for x in cost_vec] use_cvxopt = False if lp_solver.DEFAULT_LP_SOLVER_VARIANT == lp_solver.CVXOPT_SOLVER_CUSTOM_ALIGN or lp_solver.DEFAULT_LP_SOLVER_VARIANT == lp_solver.CVXOPT_SOLVER_CUSTOM_ALIGN_ILP: use_cvxopt = True if use_cvxopt: # not available in the latest version of PM4Py from cvxopt import matrix a_matrix = matrix(a_matrix) g_matrix = matrix(g_matrix) h_cvx = matrix(h_cvx) cost_vec = matrix(cost_vec) marking_dict = {} im = __encode_marking(marking_dict, model_struct[TRANSF_IM]) fm = __encode_marking(marking_dict, model_struct[TRANSF_FM]) h, x, trustable = __calculate_heuristics( None, None, im, 0, corresp, None, sync_net, incidence_matrix, fin_vec, cost_vec, a_matrix, g_matrix, h_cvx, lp_solver.DEFAULT_LP_SOLVER_VARIANT, use_cvxopt=use_cvxopt) exact_heu_calculations = 1 initial_state = (0, h, 0, 0, 0, 0, None, im, None, 0, x, trustable) open_set = [initial_state] heapq.heapify(open_set) closed = {} dummy_count = 0 visited = 0 while not len(open_set) == 0: if (time.time() - start_time) > max_align_time_trace: return None curr = heapq.heappop(open_set) curr_m0 = curr[POSITION_MARKING] curr_m = __decode_marking(curr_m0) index = curr[POSITION_INDEX] # if a situation equivalent to the one of the current state has been # visited previously, then discard this if __check_closed(closed, (curr_m0, curr[POSITION_INDEX])): continue visited = visited + 1 h = curr[POSITION_HEURISTICS] x = curr[POSITION_X] trustable = curr[POSITION_TRUSTABLE] if not trustable: if (time.time() - start_time) > max_align_time_trace: return None m, t = get_corresp_marking_and_trans(curr_m, index, corresp, None) h, x = utils.__compute_exact_heuristic_new_version( sync_net, a_matrix, h_cvx, g_matrix, cost_vec, incidence_matrix, m, fin_vec, lp_solver.DEFAULT_LP_SOLVER_VARIANT, use_cvxopt=use_cvxopt) exact_heu_calculations = exact_heu_calculations + 1 curr = list(curr) curr[POSITION_HEURISTICS] = h curr[POSITION_TOTAL_COST] = curr[POSITION_COST] + h curr[POSITION_X] = x curr[POSITION_TRUSTABLE] = True curr = tuple(curr) heapq.heappush(open_set, curr) continue __add_closed(closed, (curr_m0, curr[POSITION_INDEX])) if curr_m0 == fm: if -curr[POSITION_INDEX] == len(transf_trace): # returns the alignment only if the final marking has been reached AND # the trace is over return __reconstruct_alignment( curr, model_struct, trace_struct, visited, len(open_set), len(closed), len(marking_dict), exact_heu_calculations, ret_tuple_as_trans_desc=ret_tuple_as_trans_desc) # retrieves the transitions that are enabled in the current marking en_t = [[ t, __encode_marking( marking_dict, __fire_trans(curr_m, trans_pre_dict[t], trans_post_dict[t])), 0, None, False ] for t in trans_pre_dict if __dict_leq(trans_pre_dict[t], curr_m)] this_closed = set() j = 0 while j < len(en_t): t = en_t[j][0] # checks if a given transition can be executed in sync with the trace is_sync = trans_labels_dict[t] == transf_trace[ -curr[POSITION_INDEX]] if -curr[POSITION_INDEX] < len( transf_trace) else False if is_sync: new_m = en_t[j][1] new_h, new_x, new_trustable = __calculate_heuristics( h, x, new_m, curr[POSITION_INDEX] - 1, corresp, (curr[POSITION_INDEX], t), sync_net, incidence_matrix, fin_vec, cost_vec, a_matrix, g_matrix, h_cvx, lp_solver.DEFAULT_LP_SOLVER_VARIANT, use_cvxopt=use_cvxopt) dummy_count = dummy_count + 1 new_f = curr[POSITION_COST] + sync_cost new_g = new_f + new_h new_state = (new_g, new_h, curr[POSITION_INDEX] - 1, IS_SYNC_MOVE, curr[POSITION_ALIGN_LENGTH] + 1, dummy_count, curr, new_m, t, new_f, new_x, new_trustable) if not __check_closed( closed, (new_state[POSITION_MARKING], new_state[POSITION_INDEX])): # if it can be executed in a sync way, add a new state corresponding # to the sync execution only if it has not already been closed open_set = __add_to_open_set(open_set, new_state) # if a sync move reached new_m, do not schedule any model move that reaches new_m this_closed.add(new_m) del en_t[j] continue j = j + 1 # calculate the heuristics for the remaining states j = 0 while j < len(en_t): t = en_t[j][0] new_m = en_t[j][1] en_t[j][2], en_t[j][3], en_t[j][4] = __calculate_heuristics( h, x, new_m, curr[POSITION_INDEX], corresp, (">>", t), sync_net, incidence_matrix, fin_vec, cost_vec, a_matrix, g_matrix, h_cvx, lp_solver.DEFAULT_LP_SOLVER_VARIANT, use_cvxopt=use_cvxopt) j = j + 1 en_t.sort(key=lambda t: transf_model_cost_function[t[0]] + t[2]) j = 0 while j < len(en_t): t = en_t[j][0] new_m = en_t[j][1] new_h = en_t[j][2] new_x = en_t[j][3] new_trustable = en_t[j][4] dummy_count = dummy_count + 1 new_f = curr[POSITION_COST] + transf_model_cost_function[t] new_g = new_f + new_h new_state = (new_g, new_h, curr[POSITION_INDEX], IS_MODEL_MOVE, curr[POSITION_ALIGN_LENGTH] + 1, dummy_count, curr, new_m, t, new_f, new_x, new_trustable) if new_m not in this_closed and not curr_m0 == new_m: if not __check_closed( closed, (new_state[POSITION_MARKING], new_state[POSITION_INDEX])): open_set = __add_to_open_set(open_set, new_state) this_closed.add(new_m) j = j + 1 # IMPORTANT: to reduce the complexity, assume that you can schedule a log move # only if the previous move has not been a move-on-model. # since this setting is equivalent to scheduling all the log moves before and then # the model moves if -curr[POSITION_INDEX] < len( transf_trace) and curr[POSITION_TYPE_MOVE] != IS_MODEL_MOVE: dummy_count = dummy_count + 1 new_f = curr[POSITION_COST] + trace_cost_function[ -curr[POSITION_INDEX]] new_h, new_x, new_trustable = __calculate_heuristics( h, x, curr_m0, curr[POSITION_INDEX] - 1, corresp, (curr[POSITION_INDEX], ">>"), sync_net, incidence_matrix, fin_vec, cost_vec, a_matrix, g_matrix, h_cvx, lp_solver.DEFAULT_LP_SOLVER_VARIANT, use_cvxopt=use_cvxopt) new_g = new_f + new_h new_state = (new_g, new_h, curr[POSITION_INDEX] - 1, IS_LOG_MOVE, curr[POSITION_ALIGN_LENGTH] + 1, dummy_count, curr, curr_m0, None, new_f, new_x, new_trustable) if not __check_closed( closed, (new_state[POSITION_MARKING], new_state[POSITION_INDEX])): # adds the log move only if it has not been already closed before open_set = __add_to_open_set(open_set, new_state)
def __search(net, ini, fin): from pm4py.objects.petri.utils import decorate_places_preset_trans, decorate_transitions_prepostset cost_function = {t: 1 for t in net.transitions} decorate_transitions_prepostset(net) decorate_places_preset_trans(net) incidence_matrix = petri.incidence_matrix.construct(net) ini_vec, fin_vec, cost_vec = utils.__vectorize_initial_final_cost( incidence_matrix, ini, fin, cost_function) closed = set() a_matrix = np.asmatrix(incidence_matrix.a_matrix).astype(np.float64) g_matrix = -np.eye(len(net.transitions)) h_cvx = np.matrix(np.zeros(len(net.transitions))).transpose() cost_vec = [x * 1.0 for x in cost_vec] use_cvxopt = False if lp_solver_factory.DEFAULT_LP_SOLVER_VARIANT == lp_solver_factory.CVXOPT_SOLVER_CUSTOM_ALIGN or lp_solver_factory.DEFAULT_LP_SOLVER_VARIANT == lp_solver_factory.CVXOPT_SOLVER_CUSTOM_ALIGN_ILP: use_cvxopt = True if use_cvxopt: # not available in the latest version of PM4Py from cvxopt import matrix a_matrix = matrix(a_matrix) g_matrix = matrix(g_matrix) h_cvx = matrix(h_cvx) cost_vec = matrix(cost_vec) h, x = utils.__compute_exact_heuristic_new_version( net, a_matrix, h_cvx, g_matrix, cost_vec, incidence_matrix, ini, fin_vec, lp_solver_factory.DEFAULT_LP_SOLVER_VARIANT, use_cvxopt=use_cvxopt) ini_state = utils.SearchTuple(0 + h, 0, h, ini, None, None, x, True) open_set = [ini_state] heapq.heapify(open_set) visited = 0 queued = 0 traversed = 0 trans_empty_preset = set(t for t in net.transitions if len(t.in_arcs) == 0) while not len(open_set) == 0: curr = heapq.heappop(open_set) current_marking = curr.m # 11/10/2019 (optimization Y, that was optimization X, # but with the good reasons this way): avoid checking markings in the cycle using # the __get_alt function, but check them 'on the road' already_closed = current_marking in closed if already_closed: continue while not curr.trust: h, x = utils.__compute_exact_heuristic_new_version( net, a_matrix, h_cvx, g_matrix, cost_vec, incidence_matrix, curr.m, fin_vec, lp_solver_factory.DEFAULT_LP_SOLVER_VARIANT, use_cvxopt=use_cvxopt) # 11/10/19: shall not a state for which we compute the exact heuristics be # by nature a trusted solution? tp = utils.SearchTuple(curr.g + h, curr.g, h, curr.m, curr.p, curr.t, x, True) # 11/10/2019 (optimization ZA) heappushpop is slightly more efficient than pushing # and popping separately curr = heapq.heappushpop(open_set, tp) current_marking = curr.m # max allowed heuristics value (27/10/2019, due to the numerical instability of some of our solvers) if curr.h > lp_solver_factory.MAX_ALLOWED_HEURISTICS: continue # 12/10/2019: do it again, since the marking could be changed already_closed = current_marking in closed if already_closed: continue # 12/10/2019: the current marking can be equal to the final marking only if the heuristics # (underestimation of the remaining cost) is 0. Low-hanging fruits if curr.h < 0.01: if current_marking == fin: return utils.__reconstruct_alignment(curr, visited, queued, traversed) closed.add(current_marking) visited += 1 possible_enabling_transitions = copy(trans_empty_preset) for p in current_marking: for t in p.ass_trans: possible_enabling_transitions.add(t) enabled_trans = [ t for t in possible_enabling_transitions if t.sub_marking <= current_marking ] trans_to_visit_with_cost = [(t, cost_function[t]) for t in enabled_trans] for t, cost in trans_to_visit_with_cost: traversed += 1 new_marking = utils.add_markings(current_marking, t.add_marking) if new_marking in closed: continue g = curr.g + cost queued += 1 h, x = utils.__derive_heuristic(incidence_matrix, cost_vec, curr.x, t, curr.h) trustable = utils.__trust_solution(x) new_f = g + h tp = utils.SearchTuple(new_f, g, h, new_marking, curr, t, x, trustable) heapq.heappush(open_set, tp)
def __search(sync_net, ini, fin, stop, cost_function, skip): decorate_transitions_prepostset(sync_net) decorate_places_preset_trans(sync_net) incidence_matrix = construct(sync_net) ini_vec, fin_vec, cost_vec = utils.__vectorize_initial_final_cost( incidence_matrix, ini, fin, cost_function) closed = set() ini_state = utils.SearchTuple(0, 0, 0, ini, None, None, None, True) open_set = [ini_state] heapq.heapify(open_set) visited = 0 queued = 0 traversed = 0 # return all the prefix markings of the optimal alignments as set ret_markings = None # keep track of the optimal cost of an alignment (to trim search when needed) optimal_cost = None while not len(open_set) == 0: curr = heapq.heappop(open_set) current_marking = curr.m # trim alignments when we already reached an optimal alignment and the # current cost is greater than the optimal cost if optimal_cost is not None and curr.f > optimal_cost: break already_closed = current_marking in closed if already_closed: continue if stop <= current_marking: # add the current marking to the set # of returned markings if ret_markings is None: ret_markings = set() ret_markings.add(current_marking) # close the marking closed.add(current_marking) # set the optimal cost optimal_cost = curr.f continue closed.add(current_marking) visited += 1 possible_enabling_transitions = set() for p in current_marking: for t in p.ass_trans: possible_enabling_transitions.add(t) enabled_trans = [ t for t in possible_enabling_transitions if t.sub_marking <= current_marking ] trans_to_visit_with_cost = [ (t, cost_function[t]) for t in enabled_trans if not (t is None or utils.__is_log_move(t, skip) or ( utils.__is_model_move(t, skip) and not t.label[1] is None)) ] for t, cost in trans_to_visit_with_cost: traversed += 1 new_marking = utils.add_markings(current_marking, t.add_marking) if new_marking in closed: continue g = curr.g + cost queued += 1 new_f = g tp = utils.SearchTuple(new_f, g, 0, new_marking, curr, t, None, True) heapq.heappush(open_set, tp) return ret_markings
def __search(sync_net, ini, fin, cost_function, skip, ret_tuple_as_trans_desc=False, max_align_time_trace=sys.maxsize): start_time = time.time() decorate_transitions_prepostset(sync_net) decorate_places_preset_trans(sync_net) incidence_matrix = inc_mat_construct(sync_net) ini_vec, fin_vec, cost_vec = utils.__vectorize_initial_final_cost( incidence_matrix, ini, fin, cost_function) closed = set() heu_dict = {} heu_max_ind_dict = {} mtcgt_dict = {} parameters = {} parameters[marking_equation.Parameters.FULL_BOOTSTRAP_REQUIRED] = False parameters[marking_equation.Parameters.INCIDENCE_MATRIX] = incidence_matrix parameters[marking_equation.Parameters.COSTS] = cost_function visited = 0 queued = 0 traversed = 0 me = marking_equation.build(sync_net, ini, fin, parameters=parameters) h, x = me.solve() lp_solved = 1 # try to see if the firing sequence is already fine firing_sequence, reach_fm, explained_events = me.get_firing_sequence(x) if reach_fm: return __reconstruct_alignment( firing_sequence, h, visited, queued, traversed, ret_tuple_as_trans_desc=ret_tuple_as_trans_desc, lp_solved=lp_solved) mm, index = __get_model_marking_and_index(ini) __update_heu_dict(heu_dict, heu_max_ind_dict, mm, index, h, x, firing_sequence, incidence_matrix, cost_vec) ini_state = utils.TweakedSearchTuple(0 + h, 0, h, ini, None, None, x, True, False) open_set = [ini_state] heapq.heapify(open_set) trans_empty_preset = set(t for t in sync_net.transitions if len(t.in_arcs) == 0) while not len(open_set) == 0: if (time.time() - start_time) > max_align_time_trace: return None curr = heapq.heappop(open_set) current_marking = curr.m while not curr.trust: if (time.time() - start_time) > max_align_time_trace: return None already_closed = current_marking in closed if already_closed: curr = heapq.heappop(open_set) current_marking = curr.m continue if curr.t not in mtcgt_dict: lp_solved += 1 mtcgt = __min_total_cost_given_trans(me, ini, incidence_matrix, curr.t) mtcgt_dict[curr.t] = mtcgt else: mtcgt = mtcgt_dict[curr.t] h1 = max(mtcgt - curr.g, 0) if h1 > curr.h: tp = utils.TweakedSearchTuple(curr.g + h1, curr.g, h1, curr.m, curr.p, curr.t, curr.x, False, False) curr = heapq.heappushpop(open_set, tp) current_marking = curr.m continue mm, index = __get_model_marking_and_index(curr.m) h2, x2, trust2 = __get_heu_from_dict(heu_dict, heu_max_ind_dict, mm, index) if h2 is not None and h2 > curr.h: tp = utils.TweakedSearchTuple(curr.g + h2, curr.g, h2, curr.m, curr.p, curr.t, x2, trust2, False) curr = heapq.heappushpop(open_set, tp) current_marking = curr.m continue me.change_ini_vec(curr.m) h, x = me.solve() __update_heu_dict_specific_point(heu_dict, heu_max_ind_dict, mm, index, h, x) lp_solved += 1 tp = utils.TweakedSearchTuple(curr.g + h, curr.g, h, curr.m, curr.p, curr.t, x, True, True) curr = heapq.heappushpop(open_set, tp) current_marking = curr.m already_closed = current_marking in closed if already_closed: continue if curr.h < 0.01: if current_marking == fin: trans_list = __transitions_list_from_state(curr) return __reconstruct_alignment( trans_list, curr.f, visited, queued, traversed, ret_tuple_as_trans_desc=ret_tuple_as_trans_desc, lp_solved=lp_solved) if curr.virgin: # try to see if the firing sequence is already fine firing_sequence, reach_fm, explained_events = me.get_firing_sequence( curr.x) if reach_fm: trans_list = __transitions_list_from_state(curr) + list( firing_sequence) return __reconstruct_alignment( trans_list, curr.f, visited, queued, traversed, ret_tuple_as_trans_desc=ret_tuple_as_trans_desc, lp_solved=lp_solved) mm, index = __get_model_marking_and_index(curr.m) __update_heu_dict(heu_dict, heu_max_ind_dict, mm, index, h, x, firing_sequence, incidence_matrix, cost_vec) closed.add(current_marking) visited += 1 possible_enabling_transitions = copy(trans_empty_preset) for p in current_marking: for t in p.ass_trans: possible_enabling_transitions.add(t) enabled_trans = [ t for t in possible_enabling_transitions if t.sub_marking <= current_marking ] trans_to_visit_with_cost = [ (t, cost_function[t]) for t in enabled_trans if not (t is not None and utils.__is_log_move(t, skip) and utils.__is_model_move(t, skip)) ] for t, cost in trans_to_visit_with_cost: traversed += 1 new_marking = utils.add_markings(current_marking, t.add_marking) if new_marking in closed: continue g = curr.g + cost queued += 1 h, x = utils.__derive_heuristic(incidence_matrix, cost_vec, curr.x, t, curr.h) trust = utils.__trust_solution(x) mm, index = __get_model_marking_and_index(new_marking) if not trust: h2, x2, trust2 = __get_heu_from_dict(heu_dict, heu_max_ind_dict, mm, index) if h2 is not None and (h2 > h or trust2): h = h2 x = x2 trust = trust2 else: __update_heu_dict_specific_point(heu_dict, heu_max_ind_dict, mm, index, h, x) new_f = g + h tp = utils.TweakedSearchTuple(new_f, g, h, new_marking, curr, t, x, trust, False) heapq.heappush(open_set, tp)