docstr: Find completed matches between two entities
  
  Args:
      df: dataframe
      col_a: column name a
      col_b: column name b
  
  Returns:
      A list of tuple, each item is the indices of nodes in the completed graph
docstr_tok: ["Find","completed","matches","between","two","entities","Args",":","df",":","dataframe","col_a",":","column","name","a","col_b",":","column","name","b","Returns",":","A","list","of","tuple",",","each","item","is","the","indices","of","nodes","in","the","completed","graph"]
code: def find_m_to_n_complete_matches(
      cls, df: pd.DataFrame, col_a: str, col_b: str
  ) -> List[Tuple[List[int], List[int]]]:
      """
      Find completed matches between two entities
  
      Args:
          df: dataframe
          col_a: column name a
          col_b: column name b
  
      Returns:
          A list of tuple, each item is the indices of nodes in the completed graph
      """
      processed_cols = [col_a, col_b]
      copy_df = df[processed_cols].copy(deep=True)
      copy_df = copy_df.drop_duplicates()
      sorted_unique_a_set = [
          a
          for a, _ in sorted(
              copy_df[col_a].value_counts().items(),
              key=operator.itemgetter(1),
          )[::-1]
      ]
      matches_found = []
      processed_a = set()
  
      for idx, value_a in enumerate(sorted_unique_a_set):
          if value_a in processed_a:
              continue
          b_set = set(
              copy_df[copy_df[col_a] == value_a][col_b].values
          )  # find all the connected b
          relevant_b = copy_df[col_b].isin(b_set)
          back_a_set = set(
              copy_df[relevant_b][col_a].values
          )  # find all the connected a for all the b above
          relevant_a = copy_df[col_a].isin(back_a_set)
          back_b_set = set(
              copy_df[relevant_a][col_b].values
          )  # find all the connected b for all the a above
          if len(b_set) == len(back_b_set) and b_set == back_b_set:
              m = len(back_a_set)
              n = len(back_b_set)
              logic = relevant_a & relevant_b
              relevant_mr = copy_df[logic]
              copy_df = copy_df[~logic]
              if len(relevant_mr) == m * n:
                  matches_found.append(
                      [list(back_a_set), list(back_b_set)]
                  )
          processed_a.update(back_a_set)
  
      return matches_found
  
file_path: contextual-ai/xai/data/validator/dataframe_validator.py
imports: import operator
  from collections import Counter
  from typing import List, Tuple
  import pandas
  from xai.data.exceptions import ColumnNotFound
label_desc: Use image node_id 4 for calling the DataframeValidator obj's underlying member method code with example usage: obj.find_m_to_n_complete_matches(cls, df, col_a, col_b) and returns: matches_found