code: def group_sparse_scores(
      precisions,
      n_samples,
      emp_covs,
      alpha,
      duality_gap=False,
      debug=False,
  ):
      """Compute scores used by group_sparse_covariance.
  
      The log-likelihood of a given list of empirical covariances /
      precisions.
  
      Parameters
      ----------
      precisions : numpy.ndarray, shape (n_features, n_features, n_subjects)
          estimated precisions.
  
      n_samples : array-like, shape (n_subjects,)
          number of samples used in estimating each subject in "precisions".
          n_samples.sum() must be equal to 1.
  
      emp_covs : numpy.ndarray, shape (n_features, n_features, n_subjects)
          empirical covariance matrix
  
      alpha : float
          regularization parameter
  
      duality_gap : bool, default=False
          if True, also returns a duality gap upper bound.
  
      debug : bool, default=False
          if True, some consistency checks are performed to help solving
          numerical problems.
  
      Returns
      -------
      log_lik : float
          log-likelihood of precisions on the given covariances. This is the
          opposite of the loss function, without the regularization term
  
      objective : float
          value of objective function. This is the value minimized by
          group_sparse_covariance()
  
      duality_gap : float
          duality gap upper bound. The returned bound is tight: it vanishes for
          the optimal precision matrices
  
      """
      n_features, _, n_subjects = emp_covs.shape
  
      log_lik = 0
      for k in range(n_subjects):
          log_lik_k = -np.sum(emp_covs[..., k] * precisions[..., k])
          log_lik_k += fast_logdet(precisions[..., k])
          log_lik += n_samples[k] * log_lik_k
  
      l2 = np.sqrt((precisions**2).sum(axis=-1))
      l12 = l2.sum() - np.diag(l2).sum()  # Do not count diagonal terms
      objective = alpha * l12 - log_lik
      ret = (log_lik, objective)
  
      # Compute duality gap if requested
      if duality_gap is True:
          A = np.empty(precisions.shape, dtype=np.float64, order="F")
          for k in range(n_subjects):
              # TODO: can be computed more efficiently using W_inv. See
              # Friedman, Jerome, Trevor Hastie, and Robert Tibshirani.
              # 'Sparse Inverse Covariance Estimation with the Graphical Lasso'.
              # Biostatistics 9, no. 3 (1 July 2008): 432-441.
              precisions_inv = scipy.linalg.inv(precisions[..., k])
              if debug:
                  assert is_spd(precisions_inv)
  
              A[..., k] = n_samples[k] * (
                  precisions_inv - emp_covs[..., k]
              )
  
              if debug:
                  np.testing.assert_almost_equal(A[..., k], A[..., k].T)
  
          # Project A on the set of feasible points
          alpha_max = np.sqrt((A**2).sum(axis=-1))
          mask = alpha_max > alpha
          for k in range(A.shape[-1]):
              A[mask, k] *= alpha / alpha_max[mask]
              # Set zeros on diagonals. Essential to get an always positive
              # duality gap.
              A[..., k].flat[:: A.shape[0] + 1] = 0
  
          dual_obj = 0  # dual objective
          for k in range(n_subjects):
              B = emp_covs[..., k] + A[..., k] / n_samples[k]
              dual_obj += n_samples[k] * (n_features + fast_logdet(B))
  
          # The previous computation can lead to a non-feasible point, because
          # one of the Bs may not be positive definite.
          # Use another value in this case, that ensure positive definiteness
          # of B. The upper bound on the duality gap is not tight in the
          # following, but is smaller than infinity, which is better in any case.
          if not np.isfinite(dual_obj):
              for k in range(n_subjects):
                  A[..., k] = -n_samples[k] * emp_covs[..., k]
                  A[..., k].flat[:: A.shape[0] + 1] = 0
              alpha_max = np.sqrt((A**2).sum(axis=-1)).max()
              # the second value (0.05 is arbitrary: positive in ]0,1[)
              gamma = min((alpha / alpha_max, 0.05))
              dual_obj = 0
              for k in range(n_subjects):
                  # add gamma on the diagonal
                  B = (1.0 - gamma) * emp_covs[..., k] + gamma * np.eye(
                      emp_covs.shape[0]
                  )
                  dual_obj += n_samples[k] * (
                      n_features + fast_logdet(B)
                  )
  
          gap = objective - dual_obj
          ret = ret + (gap,)
      return ret
  
imports: import collections.abc
  import itertools
  import operator
  import warnings
  import numpy
  import scipy.linalg
  from joblib import Memory, Parallel, delayed
  from sklearn.base import BaseEstimator
  from sklearn.covariance import empirical_covariance
  from sklearn.model_selection import check_cv
  from sklearn.utils.extmath import fast_logdet
  from .._utils import CacheMixin, logger
  from .._utils.extmath import is_spd
label_desc: Use image node_id 7 for calling a global function with example usage: group_sparse_scores(precisions, n_samples, emp_covs, alpha, duality_gap, debug) and returns: ret