docstr: Learn diagonal metric using MMC.
  Parameters
  ----------
  X : (n x d) data matrix
    Each row corresponds to a single instance.
  constraints : 4-tuple of arrays
    (a,b,c,d) indices into X, with (a,b) specifying similar and (c,d)
    dissimilar pairs.
docstr_tok: ["Learn","diagonal","metric","using","MMC",".","Parameters","--","--","--","--","--","X",":","(","n","x","d",")","data","matrix","Each","row","corresponds","to","a","single","instance",".","constraints",":","4-tuple","of","arrays","(","a",",","b",",","c",",","d",")","indices","into","X",",","with","(","a",",","b",")","specifying","similar","and","(","c",",","d",")","dissimilar","pairs","."]
code: def _fit_diag(self, pairs, y):
      """Learn diagonal metric using MMC.
      Parameters
      ----------
      X : (n x d) data matrix
        Each row corresponds to a single instance.
      constraints : 4-tuple of arrays
        (a,b,c,d) indices into X, with (a,b) specifying similar and (c,d)
        dissimilar pairs.
      """
      num_dim = pairs.shape[2]
      pos_pairs, neg_pairs = pairs[y == 1], pairs[y == -1]
      s_sum = np.sum(
          (pos_pairs[:, 0, :] - pos_pairs[:, 1, :]) ** 2, axis=0
      )
  
      it = 0
      error = 1.0
      eps = 1e-6
      reduction = 2.0
      w = np.diag(self.A_).copy()
  
      while error > self.tol and it < self.max_iter:
          fD0, fD_1st_d, fD_2nd_d = self._D_constraint(neg_pairs, w)
          obj_initial = np.dot(s_sum, w) + self.diagonal_c * fD0
          fS_1st_d = (
              s_sum  # first derivative of the similarity constraints
          )
  
          # gradient of the objective:
          gradient = fS_1st_d - self.diagonal_c * fD_1st_d
          # Hessian of the objective:
          hessian = -self.diagonal_c * fD_2nd_d + eps * np.eye(num_dim)
          step = np.dot(np.linalg.inv(hessian), gradient)
  
          # Newton-Rapshon update
          # search over optimal lambda
          lambd = 1  # initial step-size
          w_tmp = np.maximum(0, w - lambd * step)
          obj = np.dot(
              s_sum, w_tmp
          ) + self.diagonal_c * self._D_objective(neg_pairs, w_tmp)
          assert_all_finite(obj)
          obj_previous = np.inf  # just to get the while-loop started
  
          inner_it = 0
          while obj < obj_previous:
              obj_previous = obj
              w_previous = w_tmp.copy()
              lambd /= reduction
              w_tmp = np.maximum(0, w - lambd * step)
              obj = np.dot(
                  s_sum, w_tmp
              ) + self.diagonal_c * self._D_objective(neg_pairs, w_tmp)
              inner_it += 1
              assert_all_finite(obj)
  
          w[:] = w_previous
          error = np.abs((obj_previous - obj_initial) / obj_previous)
          if self.verbose:
              print("mmc iter: %d, conv = %f" % (it, error))
          it += 1
  
      self.A_ = np.diag(w)
  
      self.components_ = components_from_metric(self.A_)
      return self
  
imports: import numpy
  from sklearn.base import TransformerMixin
  from sklearn.utils.validation import assert_all_finite
  from .base_metric import _PairsClassifierMixin, MahalanobisMixin
  from .constraints import Constraints, wrap_pairs
  from ._util import components_from_metric, _initialize_metric_mahalanobis
  import warnings
label_desc: Use image node_id 4 for calling the _BaseMMC obj's underlying member method code with example usage: obj._fit_diag(pairs, y) and returns: self