code: 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