def query_processing_algo4(u, m, cell_u_position_info, query_obj, learned_dict_start, learned_dict_arrival):
    """
    Algorithm 4 :: Query processing using two-level friend list
    :param u: userID
    :param m: the number of seats of a vehicle
    :param cell_u_position_info: client information
    :param query_obj: query system(DB system)
    :return:
    """
    #IO_count
    IO_count=0

    #저번 epoch 흔적 지우기
    cell_u_position_info.VH = set()
    cell_u_position_info.CS = set()

    p = query_obj.SELECT_position_WHERE_userid(u)
    t = query_obj.SELECT_time_WHERE_userid(u)

    # Line 3
    best_cost=100000

    # new exit condition
    group_generating_flag=False
    top_m_minus_1 = list()
    top_m_minus_1_mc = list()
    threshold_cost = 10000
    threshold = 0
    first_vertex = True
    candidate_cost = 0

    # defining necessary minheap
    cell_u_position_info.VH=tree_algorithm.MinHeap_moving_cost(p, query_obj)
    candidate_list=tree_algorithm.MinHeap_moving_cost(p, query_obj)

    # computing group obj
    # group 연산에 대한 메소드를 가진 오브젝트
    compute_group_obj = compute_group_algo4.ComputeGroup_algo4(m, p, query_obj)
    optimal_group=set()

    #셀들 전부 다 넣고 시작
    DH, AH = cell_u_position_info.find_cover_cell(u, query_obj, learned_dict_start, learned_dict_arrival, 0.01)  # return (SH, EH)
    print("[simulator] complete to make cell heap")
    start_time = time.time()

    # Line 5
    if True: #originally this statement is for the number of friend inspection
        # Line 6 : 친구들이 커버하고 있는 셀 찾기. 여기를 고쳐야한다. 1. 모든 셀 다 넣어버리던가
        # Line 7
        while not DH.is_empty() or not AH.is_empty():
            # Line 8
            if not DH.is_empty():
                cd=DH.delete()
            # Line 9
            if not AH.is_empty():
                ca=AH.delete()

            # Line 10
            if group_generating_flag:
                if best_cost - candidate_cost < DH.mindist_user_and_cell(cd) + AH.mindist_user_and_cell(ca):    #>>overhead
                    # Line 11
                    break

            IO_flag = cell_u_position_info.search_cell_data_algo4(u, query_obj, cd, t, True) # it is from start cell
            if IO_flag:
                IO_count=IO_count+1

            # Line 13
            IO_flag = cell_u_position_info.search_cell_data_algo4(u, query_obj, ca, t, False) # it is from end cell
            if IO_flag:
                IO_count=IO_count+1

            # Line 14
            while not cell_u_position_info.is_VH_empty():
                # Line 15
                selected_vertex=cell_u_position_info.VH.delete()
                # Line 16
                selected_vertex_position = query_obj.SELECT_position_WHERE_userid(selected_vertex)
                selected_vertex_mc = cell_u_position_info.VH.moving_cost(selected_vertex_position)

                if m!=2:
                    if len(top_m_minus_1)<m-2:
                        top_m_minus_1.append(selected_vertex)
                        top_m_minus_1_mc.append(selected_vertex_mc)

                        if first_vertex:
                            first_vertex = False
                            threshold = selected_vertex
                            threshold_cost = selected_vertex_mc

                        if threshold_cost < selected_vertex_mc:
                            threshold = selected_vertex
                            threshold_cost = selected_vertex_mc

                    else:   #m-1이 되면!
                        if threshold_cost > selected_vertex_mc:
                            top_m_minus_1.remove(threshold)
                            top_m_minus_1_mc.remove(threshold_cost)
                            top_m_minus_1.append(selected_vertex)
                            top_m_minus_1_mc.append(selected_vertex_mc)
                            candidate_cost = compute_group_obj.group_moving_cost(set(top_m_minus_1))

                            #threshold를 정하는 반복문
                            max = top_m_minus_1_mc[0]
                            max_index = 0
                            for index, mc in enumerate(top_m_minus_1_mc):
                                if max < mc:
                                    max = mc
                                    max_index = index

                            threshold_cost = top_m_minus_1_mc[max_index]
                            threshold = top_m_minus_1[max_index]

                if group_generating_flag:
                    if best_cost - candidate_cost < selected_vertex_mc:
                        # Line 17
                        break

                # Line 18
                if selected_vertex not in candidate_list.heap:
                    computed_group=compute_group_obj.find_min_mc_group(selected_vertex, candidate_list, m)

                # Line 19
                if len(computed_group)+1 >= m:  #user도 포함해서 계산해야한다.
                    group_moving_cost = compute_group_obj.group_moving_cost(computed_group)
                    if best_cost > group_moving_cost:
                        # Line 24
                        optimal_group=computed_group.copy()
                        # Line 25
                        best_cost=group_moving_cost
                        # Line 26
                        group_generating_flag = True

    result_time=time.time()-start_time
    print(candidate_cost, best_cost)
    return (optimal_group.union({u}), result_time, IO_count)
def query_processing_algo4(u, l, m, cell_u_position_info, query_obj, friend_obj):
    """
    Algorithm 4 :: Query processing using two-level friend list
    :param u: userID
    :param l: an acceptable social boundary
    :param m: the number of seats of a vehicle
    :return:
    """
    #IO_count
    IO_count=0

    #저번 epoch 흔적 지우기
    cell_u_position_info.VH = set()
    cell_u_position_info.CS = set()

    p = query_obj.SELECT_position_WHERE_userid(u)
    t = query_obj.SELECT_time_WHERE_userid(u)

    # Line 3
    best_cost=10000

    # new exit condition
    group_generating_flag=False
    top_m_minus_1 = list()
    top_m_minus_1_mc = list()
    threshold_cost = 10000
    threshold = 0
    first_vertex = True
    candidate_cost = 0

    # defining necessary minheap
    cell_u_position_info.VH=tree_algorithm.MinHeap_moving_cost(p, query_obj)
    candidate_list=tree_algorithm.MinHeap_moving_cost(p, query_obj)

    # computing group obj
    # group 연산에 대한 메소드를 가진 오브젝트
    compute_group_obj = compute_group_algo4.ComputeGroup_algo4(m, friend_obj, p, query_obj)
    optimal_group=set()

    start_time = time.time()
    # Line 4
    user_friend_list=friend_obj.friend_list_with_SCF(u, l)[0] #이거 return 값 업데이트 되었다.

    # Line 5
    if m<=len(user_friend_list.union({u})):
        # print("length of user list: "+str(len(user_friend_list)))

        # Line 6 : 친구들이 커버하고 있는 셀 찾기. >> overhead
        start_time1=time.time()
        DH, AH = cell_u_position_info.find_cover_cell(u, user_friend_list, query_obj)   # return (SH, EH)
        # print("finding cover cell: "+str(time.time()-start_time1))

        # Line 7
        while not DH.is_empty() or not AH.is_empty():
            # Line 8
            if not DH.is_empty():
                cd=DH.delete()
            # Line 9
            if not AH.is_empty():
                ca=AH.delete()

            # Line 10
            if group_generating_flag:
                if best_cost - candidate_cost < DH.mindist_user_and_cell(cd) + AH.mindist_user_and_cell(ca):    #>>overhead
                    # Line 11
                    break
            #print(DH.mindist_user_and_cell(cd) , AH.mindist_user_and_cell(ca))
            IO_flag = cell_u_position_info.search_cell_data_algo4(query_obj, cd, user_friend_list, t, True) # it is from start cell
            if IO_flag:
                IO_count=IO_count+1

            # Line 13
            IO_flag = cell_u_position_info.search_cell_data_algo4(query_obj, ca, user_friend_list, t, False) # it is from end cell
            if IO_flag:
                IO_count=IO_count+1

            # Line 14
            while not cell_u_position_info.is_VH_empty():
                # Line 15
                selected_vertex=cell_u_position_info.VH.delete()
                # Line 16
                selected_vertex_position = query_obj.SELECT_position_WHERE_userid(selected_vertex)
                selected_vertex_mc = cell_u_position_info.VH.moving_cost(selected_vertex_position)

                #candidate 갱신이 여기서 이루어져야 한다.
                if m!=2:
                    if len(top_m_minus_1)<m-2:
                        top_m_minus_1.append(selected_vertex)
                        top_m_minus_1_mc.append(selected_vertex_mc)

                        if first_vertex:
                            first_vertex = False
                            threshold = selected_vertex
                            threshold_cost = selected_vertex_mc

                        if threshold_cost < selected_vertex_mc:
                            threshold = selected_vertex
                            threshold_cost = selected_vertex_mc

                    else:   #m-1이 되면!
                        if threshold_cost > selected_vertex_mc:
                            top_m_minus_1.remove(threshold)
                            top_m_minus_1_mc.remove(threshold_cost)
                            top_m_minus_1.append(selected_vertex)
                            top_m_minus_1_mc.append(selected_vertex_mc)
                            candidate_cost = compute_group_obj.group_moving_cost(set(top_m_minus_1))

                            #threshold를 정하는 반복문
                            max = top_m_minus_1_mc[0]
                            max_index = 0
                            for index, mc in enumerate(top_m_minus_1_mc):
                                if max < mc:
                                    max = mc
                                    max_index = index

                            threshold_cost = top_m_minus_1_mc[max_index]
                            threshold = top_m_minus_1[max_index]

                if group_generating_flag:
                    if best_cost - candidate_cost < selected_vertex_mc:
                        # Line 17
                        break

                # Line 18
                if selected_vertex not in candidate_list.heap:
                    computed_group=compute_group_obj.find_min_mc_group_with_MFL(selected_vertex, candidate_list, l, m)

                # Line 19
                if len(computed_group)+1 >= m:  #user도 포함해서 계산해야한다.
                    group_moving_cost = compute_group_obj.group_moving_cost(computed_group)
                    if best_cost > group_moving_cost:
                        # Line 24
                        optimal_group=computed_group.copy()
                        # Line 25
                        best_cost=group_moving_cost
                        # Line 26
                        group_generating_flag = True
                        # candiCost 갱신
                        # copied_heap = copy.deepcopy(candidate_list)
                        # top_m_minus_1.clear()
                        # for count in range(m-2):
                        #     best_vertex = copied_heap.delete()
                        #     top_m_minus_1.append(best_vertex)
                        # candidate_cost = compute_group_obj.group_moving_cost(set(top_m_minus_1))
    result_time=time.time()-start_time
    print(candidate_cost)
    print(best_cost)
    return (optimal_group.union({u}), result_time, IO_count)
def query_processing_algo4(u, m, cell_u_position_info, query_obj, grid_length):
    """
    Algorithm 4 :: Query processing using two-level friend list
    :param u: userID
    :param m: the number of seats of a vehicle
    :param cell_u_position_info: client information
    :param query_obj: query system(DB system)
    :param grid_length: grid length(only for v.naive)
    :return:
    """
    #count IO
    IO_count = 0
    best_cost = 100000
    #저번 epoch 흔적 지우기
    cell_u_position_info.VH = set()
    cell_u_position_info.CS = set()

    #candidate cost 추출을 위한 변수
    group_generating_flag = False
    top_m_minus_1 = list()
    top_m_minus_1_mc = list()
    threshold_cost = 10000
    threshold = 0
    first_vertex = True
    candidate_cost = 0

    p = query_obj.SELECT_position_WHERE_userid(u)
    t = query_obj.SELECT_time_WHERE_userid(u)
    cell_u_position_info.VH = tree_algorithm.MinHeap_moving_cost(p, query_obj)

    # CPM 객체 생성
    cpm = pseudo_pcm.CPM(u, query_obj, grid_length, cell_u_position_info)
    best_group = set()

    # DECLARE SET
    departure_set = set()
    arrival_set = set()
    intermediate_set = tree_algorithm.MinHeap_moving_cost(p, query_obj)

    # 그룹을 생성하는 객체 생성
    compute_group_obj = compute_group_algo4.ComputeGroup_algo4(m, p, query_obj)

    #start
    start_time = time.time()

    if True:  #originally this statement is for the number of friend inspection
        while True:  #not DH.is_empty() and not AH.is_empty():
            # CPM으로 vertex하나씩 꺼내는 코드
            start_vertex = cpm.pop(True)
            while start_vertex == -1 or start_vertex == u:  #-1이 return되면 계속해서 탐색해야하고, user와 같은 vertex는 무시한다.
                start_vertex = cpm.pop(True)

            end_vertex = cpm.pop(False)
            while end_vertex == -1 or end_vertex == u:  #위와 같은 이유이다.
                end_vertex = cpm.pop(False)

            if start_vertex == -2 and end_vertex == -2:  # 한 쪽에서라도 더 이상 탐색할 cell이 없다면, break한다
                break

            #line 8-9 : step of filtering veretx
            if group_generating_flag:
                if best_cost - candidate_cost < cpm.start_min_dist_cell + cpm.end_min_dist_cell:
                    break

            # getting start-info phase
            start_vertex_position = query_obj.SELECT_position_WHERE_userid(
                start_vertex)
            mc_start_vertex = cpm.start_vertex_minheap.moving_cost(
                start_vertex_position)
            start_vertex_time = query_obj.SELECT_time_WHERE_userid(
                start_vertex)
            dist_vertex_position = cpm.start_vertex_minheap.dist(
                start_vertex_position[0], start_vertex_position[1])

            if (mc_start_vertex < dist_vertex_position
                ) and check_time_condition(t, start_vertex_time):
                departure_set.add(start_vertex)

            # getting end-info phase
            end_vertex_position = query_obj.SELECT_position_WHERE_userid(
                end_vertex)
            mc_end_vertex = cpm.start_vertex_minheap.moving_cost(
                end_vertex_position)
            end_vertex_time = query_obj.SELECT_time_WHERE_userid(end_vertex)
            dist_vertex_position = cpm.start_vertex_minheap.dist(
                end_vertex_position[0], end_vertex_position[1])

            if (mc_end_vertex<dist_vertex_position)\
                and check_time_condition(t, end_vertex_time):
                arrival_set.add(end_vertex)

            # line 12- : 그룹 검사하기
            added_vertex_set = set()
            added_vertex_set.add(start_vertex)
            added_vertex_set.add(end_vertex)

            for vertex in added_vertex_set:
                selected_vertex_position = query_obj.SELECT_position_WHERE_userid(
                    vertex)
                selected_vertex_mc = cell_u_position_info.VH.moving_cost(
                    selected_vertex_position)
                if m != 2:
                    if len(top_m_minus_1) < m - 2:
                        top_m_minus_1.append(vertex)
                        top_m_minus_1_mc.append(selected_vertex_mc)

                        if first_vertex:
                            first_vertex = False
                            threshold = vertex
                            threshold_cost = selected_vertex_mc

                        if threshold_cost < selected_vertex_mc:
                            threshold = vertex
                            threshold_cost = selected_vertex_mc

                    else:  # m-1이 되면!
                        if threshold_cost > selected_vertex_mc:
                            top_m_minus_1.remove(threshold)
                            top_m_minus_1_mc.remove(threshold_cost)
                            top_m_minus_1.append(vertex)
                            top_m_minus_1_mc.append(selected_vertex_mc)
                            candidate_cost = compute_group_obj.group_moving_cost(
                                set(top_m_minus_1))

                            # threshold를 정하는 반복문
                            max = top_m_minus_1_mc[0]
                            max_index = 0
                            for index, mc in enumerate(top_m_minus_1_mc):
                                if max < mc:
                                    max = mc
                                    max_index = index

                            threshold_cost = top_m_minus_1_mc[max_index]
                            threshold = top_m_minus_1[max_index]

                if (vertex in departure_set) or (vertex in arrival_set):
                    if vertex not in intermediate_set.heap:  #intermediate_set에 새로운 vetex가 추가 된다면 그룹을 만들어야한다.
                        computed_group = compute_group_obj.find_min_mc_group(
                            vertex, intermediate_set,
                            m)  #메소드 안 쪽에서 vertex를 intermediate set에 추가해준다.
                        if len(computed_group) + 1 >= m:
                            current_cost = compute_group_obj.group_moving_cost(
                                computed_group)

                            if current_cost < best_cost:
                                best_group = computed_group
                                best_cost = compute_group_obj.group_moving_cost(
                                    best_group)
                                group_generating_flag = True

    print(best_cost, candidate_cost)
    result_time = time.time() - start_time
    IO_count = cpm.IO_count
    return (best_group.union({u}), result_time, IO_count)