def fgss_individ_for_nets(
        pvalues: np.ndarray,
        a_max: float = 0.5,
        score_function: Callable[[np.ndarray, np.ndarray, np.ndarray], np.ndarray] = ScoringFunctions.get_score_bj_fast,
    ) -> tuple[float, np.ndarray, np.ndarray, float]:
        """
        Finds the highest scoring subset of records and attribute. Return the subsets, the score, and the alpha that
        maximizes the score.

        A simplified, faster, exact method but only useable when scoring an individual input. This method recognizes
        that for an individual input, the priority function for a fixed alpha threshold results in all nodes having
        either priority 1 or 0. That is, the pmax is either below the threshold or not. Due to convexity of the scoring
        function we know elements with tied priority are either all included or all excluded. Therefore, each alpha
        threshold uniquely defines a single subset of nodes to be scored. These are the nodes that have pmax less than
        threshold. This means the individual-input scanner is equivalent to sorting pmax values and iteratively adding
        the next largest pmax. There are at most O(N) of these subsets to consider. Sorting requires O(N ln N). There is
        no iterative ascent required and no special choice of alpha thresholds for speed improvements.

        :param pvalues: pvalue ranges.
        :param a_max: alpha max. determines the significance level threshold
        :param score_function: scoring function
        :return: (best_score, image_sub, node_sub, optimal_alpha)
        """
        pmaxes = np.reshape(pvalues[:, 1], pvalues.shape[0])  # should be number of columns/nodes
        # we can ignore any pmax that is greater than a_max; this makes sorting faster
        # all the pvalues less than equal a_max are kept by nonzero result of the comparison
        potential_thresholds = pmaxes[np.flatnonzero(pmaxes <= a_max)]

        # sorrted_unique provides our alpha thresholds that we will scan
        # count_unique (in cumulative format) will provide the number of observations less than corresponding alpha
        sorted_unique, count_unique = np.unique(potential_thresholds, return_counts=True)

        cumulative_count = np.cumsum(count_unique)
        # In individual input case we have n_a = N, so cumulative count is used for both.
        # sorted_unique provides the increasing alpha values that need to be checked.
        vector_of_scores = score_function(cumulative_count, cumulative_count, sorted_unique)

        # scoring completed, now grab the max (and index)
        best_score_idx = np.argmax(vector_of_scores)
        best_score = vector_of_scores[best_score_idx]
        optimal_alpha = sorted_unique[best_score_idx]
        # best_size = cumulative_count[best_score_idx]

        # In order to determine which nodes are included, we look for all pmaxes less than or equal best alpha
        node_sub = np.flatnonzero(pvalues[:, 1] <= optimal_alpha)
        # in the individual input case there's only 1 possible subset of inputs to return - a 1x1 with index 0
        image_sub = np.array([0])

        return best_score, image_sub, node_sub, optimal_alpha

        Finds the highest scoring subset of records and attribute. Return the subsets, the score, and the alpha that
        maximizes the score.

        A simplified, faster, exact method but only useable when scoring an individual input. This method recognizes
        that for an individual input, the priority function for a fixed alpha threshold results in all nodes having
        either priority 1 or 0. That is, the pmax is either below the threshold or not. Due to convexity of the scoring
        function we know elements with tied priority are either all included or all excluded. Therefore, each alpha
        threshold uniquely defines a single subset of nodes to be scored. These are the nodes that have pmax less than
        threshold. This means the individual-input scanner is equivalent to sorting pmax values and iteratively adding
        the next largest pmax. There are at most O(N) of these subsets to consider. Sorting requires O(N ln N). There is
        no iterative ascent required and no special choice of alpha thresholds for speed improvements.

        :param pvalues: pvalue ranges.
        :param a_max: alpha max. determines the significance level threshold
        :param score_function: scoring function
        :return: (best_score, image_sub, node_sub, optimal_alpha)
        
art/defences/detector/evasion/subsetscanning/scanner.py