def calculate_maximum_potential_edge_counts(channel_composition, N, max_ble_span):
    """Computes the maximum number of possible occurrences per potential edge type.

    Parameters
    ----------
    channel_composition : Dict[str, int]
        Channel composition description.
    N : int
        Number of BLEs in the cluster.
    max_ble_span : int
        Maximum BLE span in the pattern.
    
    Returns
    -------
    Dict[str, int]
        Maximum number of occurrences of each edge type. 
    """

    back_dir = {'L' : 'R', 'R' : 'L', 'U' : 'D', 'D' : 'U'}

    counts = {}
    for src_ble in range(0, N):
        for sink_ble in range(max(0, src_ble - max_ble_span),\
                              min(N - 1, src_ble + max_ble_span) + 1):
            for w_src in channel_composition:
                src_dirs = ('L', 'R')
                if w_src[0] == 'V':
                    src_dirs = ('U', 'D')
                for src_dir in src_dirs:
                    for w_sink in channel_composition:
                        sink_dirs = ('L', 'R')
                        if w_sink[0] == 'V':
                            sink_dirs = ('U', 'D')
                        for sink_dir in sink_dirs:
                            if sink_dir == back_dir[src_dir]:
                                continue
                            inc = channel_composition[w_src] * channel_composition[w_sink]
                            try:
                                counts[(w_src, w_sink)] += inc 
                            except:
                                counts.update({(w_src, w_sink) : inc})

    e_str = lambda e : "potential_edge__%s%s__%s%s"\
          % (e[0], "_tap_0" if e[0][0] == 'V' else '',\
             e[1], "_tap_0" if e[1][0] == 'V' else '')

    return {e_str(e) : counts[e] for e in counts}