docs: def normalize_dense(M, norm="frag", order=1, iterations=3):
      """Apply one of the many normalization types to input dense
      matrix. Will also apply any callable norms such as a user-made
      or a lambda function.
      """
  
      s = np.array(M, np.float64)
      floatorder = np.float64(order)
  
      if norm == "SCN":
          for _ in range(0, iterations):
  
              sumrows = s.sum(axis=1)
              maskrows = (sumrows != 0)[:, None] * (sumrows != 0)[None, :]
              sums_row = sumrows[:, None] * np.ones(sumrows.shape)[None, :]
              s[maskrows] = 1. * s[maskrows] / sums_row[maskrows]
  
              sumcols = s.sum(axis=0)
              maskcols = (sumcols != 0)[:, None] * (sumcols != 0)[None, :]
              sums_col = sumcols[None, :] * np.ones(sumcols.shape)[:, None]
              s[maskcols] = 1. * s[maskcols] / sums_col[maskcols]
  
      elif norm == "mirnylib":
          try:
              from mirnylib import numutils as ntls
              s = ntls.iterativeCorrection(s, iterations)[0]
          except ImportError as e:
              print(str(e))
              print("I can't find mirnylib.")
              print("Please install it from "
                    "https://bitbucket.org/mirnylab/mirnylib")
              print("I will use default norm as fallback.")
              return normalize_dense(M, order=order, iterations=iterations)
  
      elif norm == "frag":
          for _ in range(1, iterations):
              s_norm_x = np.linalg.norm(s, ord=floatorder, axis=0)
              s_norm_y = np.linalg.norm(s, ord=floatorder, axis=1)
              s_norm = np.tensordot(s_norm_x, s_norm_y, axes=0)
              s[s_norm != 0] = 1. * s[s_norm != 0] / s_norm[s_norm != 0]
  
      elif norm == "global":
          s_norm = np.linalg.norm(s, ord=floatorder)
          s /= 1. * s_norm
  
      elif callable(norm):
          s = norm(M)
  
      else:
          print("Unknown norm. Returning input as fallback")
  
      return (s + s.T) / 2