def three_layer_FPR(reference_patterns, estimated_patterns):
    validate(reference_patterns, estimated_patterns)
    def compute_first_layer_PR(ref_occs, est_occs):
        s = len(_occurrence_intersection(ref_occs, est_occs))
        precision = s / float(len(ref_occs))
        recall = s / float(len(est_occs))
        return precision, recall
    def compute_second_layer_PR(ref_pattern, est_pattern):
        F_1 = compute_layer(ref_pattern, est_pattern)
        precision = np.mean(np.max(F_1, axis=0))
        recall = np.mean(np.max(F_1, axis=1))
        return precision, recall
    def compute_layer(ref_elements, est_elements, layer=1):
        if layer != 1 and layer != 2:
            raise ValueError("Layer (%d) must be an integer between 1 and 2"
                             % layer)
        nP = len(ref_elements)
        nQ = len(est_elements)
        F = np.zeros((nP, nQ))
        for iP in range(nP):
            for iQ in range(nQ):
                if layer == 1:
                    func = compute_first_layer_PR
                elif layer == 2:
                    func = compute_second_layer_PR
                precision, recall = func(ref_elements[iP], est_elements[iQ])
                F[iP, iQ] = util.f_measure(precision, recall)
        return F
    if _n_onset_midi(reference_patterns) == 0 or \
       _n_onset_midi(estimated_patterns) == 0:
        return 0., 0., 0.
    F_2 = compute_layer(reference_patterns, estimated_patterns, layer=2)
    precision_3 = np.mean(np.max(F_2, axis=0))
    recall_3 = np.mean(np.max(F_2, axis=1))
    f_measure_3 = util.f_measure(precision_3, recall_3)
    return f_measure_3, precision_3, recall_3