def _binary_search(self, x: np.ndarray, y: np.ndarray, x_random: np.ndarray, tol: float) -> np.ndarray:
        """
        Find example on decision boundary between input and random sample by binary search.

        :param x: Current example.
        :param y: True label of `x`.
        :param x_random: Random adversarial example of `x`.
        :return: The adversarial example at the decision boundary.
        """
        x_adv = x_random
        x_cln = x

        if self.estimator.clip_values is not None:
            max_value = self.estimator.clip_values[1]
        else:
            max_value = np.max(x)

        while np.linalg.norm((x_adv.flatten() - x_cln.flatten()) / max_value, ord=2) >= tol:
            self.nb_calls += 1
            x_mid = (x_cln + x_adv) / 2.0
            if self._is_adversarial(x_mid, y):
                x_adv = x_mid
            else:
                x_cln = x_mid

        return x_adv

        Find example on decision boundary between input and random sample by binary search.

        :param x: Current example.
        :param y: True label of `x`.
        :param x_random: Random adversarial example of `x`.
        :return: The adversarial example at the decision boundary.
        
art/attacks/evasion/geometric_decision_based_attack.py