# Path: unicycler/misc.py
# def weighted_average(num_1, num_2, weight_1, weight_2):
#     """
#     A simple weighted mean of two numbers.
#     """
#     weight_sum = weight_1 + weight_2
#     if weight_sum == 0:
#         return (num_1 + num_2) / 2.0
#     return num_1 * (weight_1 / weight_sum) + num_2 * (weight_2 / weight_sum)
# 
# def reverse_complement(seq):
#     """
#     Given a DNA sequences, this function returns the reverse complement sequence.
#     """
#     return ''.join([complement_base(x) for x in seq][::-1])
# 
# def get_num_agreement(num_1, num_2):
#     """
#     Returns a value between 0.0 and 1.0 describing how well the numbers agree.
#     1.0 is perfect agreement and 0.0 is the worst.
#     """
#     if num_1 == 0.0 and num_2 == 0.0:
#         return 1.0
#     if num_1 < 0.0 and num_2 < 0.0:
#         num_1 *= -1
#         num_2 *= -1
#     if num_1 * num_2 < 0.0:
#         return 0.0
#     return min(num_1, num_2) / max(num_1, num_2)


import sys
from collections import defaultdict
from .misc import weighted_average, reverse_complement, get_num_agreement
from . import settings
    from .cpp_wrappers import fully_global_alignment, path_alignment
            if last_seg == end:
                potential_result = working_path[:-1]
                if graph.get_path_length(potential_result) >= min_length:
                    final_paths.append(potential_result)
                    if len(final_paths) > settings.ALL_PATH_SEARCH_MAX_FINAL_PATHS:
                        raise TooManyPaths
            elif graph.get_path_length(working_path) <= max_length and \
                    last_seg in graph.forward_links:
                for next_seg in graph.forward_links[last_seg]:
                    max_allowed_count = graph.max_path_segment_count(next_seg, start_end_depth)
                    count_so_far = working_path.count(next_seg) + working_path.count(-next_seg)
                    if count_so_far < max_allowed_count:
                        new_working_paths.append(working_path + [next_seg])

        # If the number of working paths is too high, we give up.
        if len(working_paths) > settings.ALL_PATH_SEARCH_MAX_WORKING_PATHS:
            raise TooManyPaths
        working_paths = new_working_paths

    return final_paths


def progressive_path_find(graph, start, end, min_length, max_length, sequence, scoring_scheme,
                          expected_scaled_score):
    """
    This function is called when all_paths fails due to too many paths. It searches for paths by
    extended outward from both the start and end, making paths where the two searches meet. When
    the number of working paths gets too high, it is culled by performing alignments with the
    in-progress paths.
    """

# Path: unicycler/misc.py
# def weighted_average(num_1, num_2, weight_1, weight_2):
#     """
#     A simple weighted mean of two numbers.
#     """
#     weight_sum = weight_1 + weight_2
#     if weight_sum == 0:
#         return (num_1 + num_2) / 2.0
#     return num_1 * (weight_1 / weight_sum) + num_2 * (weight_2 / weight_sum)
# 
# def reverse_complement(seq):
#     """
#     Given a DNA sequences, this function returns the reverse complement sequence.
#     """
#     return ''.join([complement_base(x) for x in seq][::-1])
# 
# def get_num_agreement(num_1, num_2):
#     """
#     Returns a value between 0.0 and 1.0 describing how well the numbers agree.
#     1.0 is perfect agreement and 0.0 is the worst.
#     """
#     if num_1 == 0.0 and num_2 == 0.0:
#         return 1.0
#     if num_1 < 0.0 and num_2 < 0.0:
#         num_1 *= -1
#         num_2 *= -1
#     if num_1 * num_2 < 0.0:
#         return 0.0
#     return min(num_1, num_2) / max(num_1, num_2)


# Path: unicycler/path_finding.py
import sys
from collections import defaultdict
from .misc import weighted_average, reverse_complement, get_num_agreement
from . import settings
    from .cpp_wrappers import fully_global_alignment, path_alignment

            if last_seg == end:
                potential_result = working_path[:-1]
                if graph.get_path_length(potential_result) >= min_length:
                    final_paths.append(potential_result)
                    if len(final_paths) > settings.ALL_PATH_SEARCH_MAX_FINAL_PATHS:
                        raise TooManyPaths
            elif graph.get_path_length(working_path) <= max_length and \
                    last_seg in graph.forward_links:
                for next_seg in graph.forward_links[last_seg]:
                    max_allowed_count = graph.max_path_segment_count(next_seg, start_end_depth)
                    count_so_far = working_path.count(next_seg) + working_path.count(-next_seg)
                    if count_so_far < max_allowed_count:
                        new_working_paths.append(working_path + [next_seg])

        # If the number of working paths is too high, we give up.
        if len(working_paths) > settings.ALL_PATH_SEARCH_MAX_WORKING_PATHS:
            raise TooManyPaths
        working_paths = new_working_paths

    return final_paths


def progressive_path_find(graph, start, end, min_length, max_length, sequence, scoring_scheme,
                          expected_scaled_score):
    """
    This function is called when all_paths fails due to too many paths. It searches for paths by
    extended outward from both the start and end, making paths where the two searches meet. When
    the number of working paths gets too high, it is culled by performing alignments with the
    in-progress paths.
    """

    reverse_sequence = reverse_complement(sequence)