code: def _converge_estimates(
      ps: np.ndarray,
      py: np.ndarray,
      noise_matrix: np.ndarray,
      inverse_noise_matrix: np.ndarray,
      *,
      inv_noise_matrix_iterations: int = 5,
      noise_matrix_iterations: int = 3,
  ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
      """Updates py := P(true_label=k) and both `noise_matrix` and `inverse_noise_matrix`
      to be numerically consistent with each other, by iteratively updating their estimates based on
      the mathematical relationships between them.
  
      Forces numerical consistency of estimates. Each is estimated
      independently, but they are related mathematically with closed form
      equivalences. This will iteratively make them mathematically consistent.
  
      py := P(true_label=k) and the inverse noise matrix P(true_label=k_y|label=k_s) specify one
      another, meaning one can be computed from the other and vice versa.
      When numerical discrepancy exists due to poor estimation, they can be made
      to agree by repeatedly computing one from the other,
      for some a certain number of iterations (3-10 works fine.)
  
      Do not set iterations too high or performance will decrease as small
      deviations will get perturbed over and over and potentially magnified.
  
      Note that we have to first converge the inverse_noise_matrix and py,
      then we can update the noise_matrix, then repeat. This is because the
      inverse noise matrix depends on py (which is unknown/latent), but the
      noise matrix depends on ps (which is known), so there will be no change in
      the noise matrix if we recompute it when py and inverse_noise_matrix change.
  
  
      Parameters
      ----------
      ps : np.ndarray (shape (K, ) or (1, K))
          The fraction (prior probability) of each observed, NOISY class P(labels = k).
  
      py : np.ndarray (shape (K, ) or (1, K))
          The estimated fraction (prior probability) of each TRUE class P(true_label = k).
  
      noise_matrix : np.ndarray of shape (K, K), K = number of classes
          A conditional probability matrix of the form P(label=k_s|true_label=k_y) containing
          the fraction of examples in every class, labeled as every other class.
          Assumes columns of noise_matrix sum to 1.
  
      inverse_noise_matrix : np.ndarray of shape (K, K), K = number of classes
          A conditional probability matrix of the form P(true_label=k_y|labels=k_s) representing
          the estimated fraction observed examples in each class k_s, that are
          mislabeled examples from every other class k_y. If None, the
          inverse_noise_matrix will be computed from pred_probs and labels.
          Assumes columns of inverse_noise_matrix sum to 1.
  
      inv_noise_matrix_iterations : int, default = 5
          Number of times to converge inverse noise matrix with py and noise mat.
  
      noise_matrix_iterations : int, default = 3
          Number of times to converge noise matrix with py and inverse noise mat.
  
      Returns
      ------
      estimates: tuple
          Three arrays of the form (`py`, `noise_matrix`, `inverse_noise_matrix`) all
          having numerical agreement in terms of their mathematical relations.
      """
  
      for j in range(noise_matrix_iterations):
          for i in range(inv_noise_matrix_iterations):
              inverse_noise_matrix = compute_inv_noise_matrix(
                  py=py, noise_matrix=noise_matrix, ps=ps
              )
              py = compute_py(ps, noise_matrix, inverse_noise_matrix)
          noise_matrix = compute_noise_matrix_from_inverse(
              ps=ps, inverse_noise_matrix=inverse_noise_matrix, py=py
          )
  
      return py, noise_matrix, inverse_noise_matrix
  
imports: from sklearn.linear_model import LogisticRegression
  from sklearn.model_selection import StratifiedKFold
  from sklearn.metrics import confusion_matrix
  import sklearn.base
  import numpy
  import warnings
  from typing import Tuple, Union, Optional
  from cleanlab.typing import LabelLike
  from cleanlab.internal.multilabel_utils import stack_complement, get_onehot_num_classes
  from cleanlab.internal.constants import TINY_VALUE, CONFIDENT_THRESHOLDS_LOWER_BOUND, FLOATING_POINT_COMPARISON
  from cleanlab.internal.util import value_counts_fill_missing_classes, clip_values, clip_noise_rates, round_preserving_row_totals, append_extra_datapoint, train_val_split, get_num_classes, get_unique_classes, is_torch_dataset, is_tensorflow_dataset
  from cleanlab.internal.latent_algebra import compute_inv_noise_matrix, compute_py, compute_noise_matrix_from_inverse
  from cleanlab.internal.validation import assert_valid_inputs, labels_to_array
label_desc: Use image node_id 16 for calling a global function with example usage: _converge_estimates(ps, py, noise_matrix, inverse_noise_matrix) and returns: py,  noise_matrix,  inverse_noise_matrix