parameters: (
      fi: np.ndarray,
      fj: np.ndarray,
      config: Dict[str, Any],
      maskij: Optional[np.ndarray] = None,
  )
return_statement: return list(set(matches_ij).intersection(set(matches_ji)))
docstring: Match with brute force in both directions and keep consistent matches.
  
      Args:
          fi: feature descriptors of the first image
          fj: feature descriptors of the second image
          config: config parameters
          maskij: optional boolean mask of len(i descriptors) x len(j descriptors)
docstring_summary: Match with brute force in both directions and keep consistent matches.
docstring_tokens: Match with brute force in both directions and keep consistent matches .
function: def match_brute_force_symmetric(
      fi: np.ndarray,
      fj: np.ndarray,
      config: Dict[str, Any],
      maskij: Optional[np.ndarray] = None,
  ) -> List[Tuple[int, int]]:
      """Match with brute force in both directions and keep consistent matches.
  
      Args:
          fi: feature descriptors of the first image
          fj: feature descriptors of the second image
          config: config parameters
          maskij: optional boolean mask of len(i descriptors) x len(j descriptors)
      """
      matches_ij = [(a, b) for a, b in match_brute_force(fi, fj, config, maskij)]
      maskijT = maskij.T if maskij is not None else None
      matches_ji = [(b, a) for a, b in match_brute_force(fj, fi, config, maskijT)]
  
      return list(set(matches_ij).intersection(set(matches_ji)))
function_tokens: def match_brute_force_symmetric ( fi : np . ndarray , fj : np . ndarray , config : Dict [ str , Any ] , maskij : Optional [ np . ndarray ] = None , ) -> List [ Tuple [ int , int ] ] : matches_ij = [ ( a , b ) for a , b in match_brute_force ( fi , fj , config , maskij ) ] maskijT = maskij . T if maskij is not None else None matches_ji = [ ( b , a ) for a , b in match_brute_force ( fj , fi , config , maskijT ) ] return list ( set ( matches_ij ) . intersection ( set ( matches_ji ) ) )