Ejemplo n.º 1
0
def decompose_oi(classifier,
                 max_width,
                 algo,
                 only_exact=False,
                 max_num_groups=None):
    """ Decomposes given classifier into a set of order-independent subclassifiers.

    Args:
        classifier: Initial classifier.
        max_width: Maximal allowed classification width in the resulting subclassifiers.
        algo: Algorithm to use (Possible values 'icnp_oi', 'incp_blockers', 'min_similarity')
        only_exact: Whether only exact bits should be allowed (False by default).
        max_num_groups: Maximal allowed number of subclassifiers.

    Returns:
        Pair of subclassifiers list and classifier with leftover rules.
    """

    p4t_native.log("OI decomposition has started: exact={:s}".format(
        str(only_exact)))

    subclassifiers = []
    while (max_num_groups is None
           or len(subclassifiers) < max_num_groups) and len(classifier) > 0:
        bits, indices = p4t_native.best_subgroup(classifier, max_width,
                                                 only_exact, algo)
        subclassifiers.append(classifier.subset(indices).reorder(bits))
        classifier = classifier.subset(
            set(range(len(classifier))) - set(indices))

    p4t_native.log("OI decomposition has completed")

    return subclassifiers, classifier
Ejemplo n.º 2
0
def decompose_oi(classifier, max_width, algo, max_num_groups, *, 
        only_exact=False, max_candidate_groups=None, max_oi_algo='top_down'):
    """ Decomposes given classifier into a set of order-independent subclassifiers.

    Args:
        classifier: Initial classifier.
        max_width: Maximal allowed classification width in the resulting subclassifiers.
        algo: Algorithm to use (Possible values 'icnp_oi', 'incp_blockers', 'min_similarity')
        only_exact: Whether only exact bits should be allowed (False by default).
        max_num_groups: Maximal allowed number of subclassifiers.
        max_candidate_groups: The total number of candidate groups.
        max_oi_algo: The algorithm used for maximal OI (Possible values
            'top_down' and 'min_degree').

    Returns:
        Pair of subclassifiers list and classifier with leftover rules.
    """

    assert (max_candidate_groups is None 
            or max_num_groups <= max_candidate_groups)
    if max_candidate_groups is None:
        max_candidate_groups = max_num_groups

    p4t_native.log(f"OI decomposition has started: exact={only_exact}")

    indices = list(range(len(classifier)))
    oi_groups = []
    while len(oi_groups) < max_candidate_groups and len(indices) > 0:

        oi_bits, oi_indices = p4t_native.best_subgroup(classifier.subset(indices), 
                max_width, only_exact, algo, max_oi_algo)

        current_indices = [indices[i] for i in oi_indices]
        oi_groups.append(OIGroupInfo(
            classifier=classifier.subset(oi_indices).reorder(oi_bits),
            indices=current_indices
        ))
        indices = sorted(set(indices) - set(current_indices))

    p4t_native.log("OI decomposition has completed")

    oi_groups.sort(key=lambda x: len(x.indices), reverse=True)
    selected_groups = oi_groups[:max_num_groups]
    rest_indices = sorted(set(range(len(classifier))) - reduce(
        lambda x, y: x | y,
        (set(x.indices) for x in selected_groups),
        set()
    ))

    return ([x.classifier for x in selected_groups],
            classifier.subset(rest_indices))
Ejemplo n.º 3
0
def try_boolean_minimization(cls, use_resolution=False):
    """ Applies boolean minimization to a given classifier

    Args:
        cls: classifier to minimize
        use_resolution: use resolution technique (slower)

    Returns: possibly minimized version of the given classifier
    """
    p4t_native.log(f"Starting boolean minimization for {len(cls)} rules")
    result = cls.subset([])
    fill_from_native(result,
                     p4t_native.try_boolean_minimization(cls, use_resolution))
    return result
Ejemplo n.º 4
0
def weight_action_obstruction(cls):
    """ Given a classifier, weight its actions according to obstruction

    Args:
        cls: classifier

    Returns:
        a dictionary mapping actions to their weights
    """
    p4t_native.log(
        f'running weight obstruction calculation for {len(cls)} rules')
    result = p4t_native.calc_obstruction_weights(cls)
    for e in cls:
        if e.action not in result:
            result[e.action] = 0
    return result
Ejemplo n.º 5
0
def test_incremental(classifier, max_width, max_num_groups, max_traditional, *,
                     algo='icnp_blockers', max_oi_algo='min_degree',
                     max_candidate_groups=None):
    """ Test incremental updates for a classifier 

    Args:
        classifier: Test classifier.
        max_width: Maximal allowed classification width.
        max_num_groups: Maximal allowed number of groups.
        max_traditional: Maximal allowed size of traditional representation.
        algo: Algorithm to use (Possible values 'icnp_oi', 'incp_blockers', 'min_similarity')
        max_candidate_groups: The total number of candidate groups
        max_oi_algo: The algorithm used for maximal OI (Possible values
            'top_down' and 'min_degree').
    
    Returns:
        A list of Incremental Batch Stats
    """

    p4t_native.log("Running incremental updates...")

    incremental_stats = []
    num_added, lpm_groups, traditional = 0, [], classifier.subset([])
    while num_added < len(classifier):
        incremental, traditional = p4t_native.incremental_updates(
            classifier.subset(range(num_added, len(classifier))), 
            lpm_groups, traditional, max_traditional)
        incremental_stats.append(IncrementalBatchStats(incremental, traditional))
        num_added += incremental + traditional
        p4t_native.log(
            f"... incremental: {incremental}, traditional: {traditional}"
            f" total: {num_added}, ... {max_traditional}")

        if num_added < len(classifier):
            lpm_groups, traditional = minimize_oi_lpm(
                classifier.subset(range(num_added)), max_width, 
                algo, max_num_groups, max_oi_algo=max_oi_algo,
                max_candidate_groups=max_candidate_groups)

    return incremental_stats
Ejemplo n.º 6
0
def minimize_oi_lpm(classifier, max_width, algo, max_num_groups, *,
                    max_expanded_bits=None, provide_non_expanded=False,
                    max_candidate_groups=None, max_oi_algo='top_down'):
    """ Minimizes the number of subclassifiers, which are both LPM and OI.

    Args:
        classifier: Initial classifier.
        max_width: Maximal allowed classification width in the resulting subclassifiers.
        algo: Algorithm to use (Possible values 'icnp_oi', 'incp_blockers', 'min_similarity')
        max_num_groups: Maximal allowed number of subclassifiers.
        max_expanded_bits: Maximal allowed number of expanded bits.
        provide_non_expanded: Whether non-expanded versions should be returned.
        max_candidate_groups: The total number of candidate groups
        max_oi_algo: The algorithm used for maximal OI (Possible values
            'top_down' and 'min_degree').

    Returns:
        Pair of subclassifiers list and classifier with leftover rules. If
        provide_non_expanded is True, then the third element in a tuple  is
        a list of non-expanded classifiers.
    """
    assert max_expanded_bits is not None or not provide_non_expanded
    assert (max_candidate_groups is None 
            or max_num_groups <= max_candidate_groups)

    if max_candidate_groups is None:
        max_candidate_groups = max_num_groups

    indices = list(range(len(classifier)))
    lpm_groups = []

    while len(indices) > 0 and len(lpm_groups) < max_candidate_groups:
        p4t_native.log(f"OI-LPM has started for group #{len(lpm_groups) + 1}")

        oi_bits, oi_indices = p4t_native.best_subgroup(
            classifier.subset(indices), max_width, False, algo, max_oi_algo
        )
        oi_classifier = classifier.subset(
            indices[i] for i in oi_indices
        ).reorder(oi_bits)

        if max_expanded_bits is None:
            [[bitchain]], [[lpm_indices]] = p4t_native.min_bmgr(
                [oi_classifier], 1
            )
            group = oi_classifier.subset(lpm_indices).reorder(
                _chain2bits(bitchain, oi_classifier.bit_width)
            )
            nexp_group = None
        else:
            bitchain, lpm_indices, expansions = p4t_native.min_bmgr1_w_expansions(
                oi_classifier, max_expanded_bits)

            group = oi_classifier.subset([])
            for i, exp in zip(lpm_indices, expansions):
                for entry in expand(oi_classifier[i], exp):
                    group.vmr.append(entry)

            if provide_non_expanded:
                nexp_group = oi_classifier.subset(lpm_indices).reorder(
                    _chain2bits(bitchain, oi_classifier.bit_width)
                )
            else:
                nexp_group = None

        current_indices = [indices[oi_indices[i]] for i in lpm_indices]
        lpm_groups.append(LPMGroupInfo(
            classifier=group, 
            nexp_classifier=nexp_group, 
            indices=current_indices
        ))

        indices = sorted(set(indices) - set(current_indices))

        p4t_native.log("OI decomposition has finished")
    
    lpm_groups.sort(key = lambda x: len(x.indices), reverse=True)
    selected_groups = lpm_groups[:max_num_groups]
    rest_indices = sorted(set(range(len(classifier))) - reduce(
        lambda x, y: x | y,
        (set(x.indices) for x in selected_groups),
        set()
    ))

    if provide_non_expanded:
        return (
            [x.classifier for x in selected_groups], 
            classifier.subset(rest_indices), 
            [x.nexp_classifier for x in selected_groups]
        )
    else:
        return (
            [x.classifier for x in selected_groups], 
            classifier.subset(rest_indices)
        )
Ejemplo n.º 7
0
def minimize_oi_lpm(classifier,
                    max_width,
                    algo,
                    max_num_groups,
                    max_expanded_bits=None,
                    provide_non_expanded=False):
    """ Minimizes the number of subclassifiers, which are both LPM and OI.

    Args:
        classifier: Initial classifier.
        max_width: Maximal allowed classification width in the resulting subclassifiers.
        algo: Algorithm to use (Possible values 'icnp_oi', 'incp_blockers', 'min_similarity')
        max_num_groups: Maximal allowed number of subclassifiers.
        max_expanded_bits: Maximal allowed number of expanded bits.
        provide_non_expanded: Whether non-expanded versions should be returned.

    Returns:
        Pair of subclassifiers list and classifier with leftover rules. If
        provide_non_expanded is True, then the third element in a tuple  is
        a list of non-expanded classifiers.
    """
    assert max_expanded_bits is not None or not provide_non_expanded

    subclassifiers = []
    non_expanded_subclassifiers = []
    while len(classifier) > 0 and len(subclassifiers) < max_num_groups:
        p4t_native.log("OI-LPM has started for group #{:d}".format(
            len(subclassifiers) + 1))

        oi_bits, oi_indices = p4t_native.best_subgroup(classifier, max_width,
                                                       False, algo)
        oi_classifier = classifier.subset(oi_indices).reorder(oi_bits)

        if max_expanded_bits is None:
            [[bitchain]], [[lpm_indices]
                           ] = p4t_native.min_bmgr([oi_classifier], 1)
            subclassifiers.append(
                oi_classifier.subset(lpm_indices).reorder(
                    _chain2bits(bitchain, oi_classifier.bit_width)))
        else:
            bitchain, lpm_indices, expansions = p4t_native.min_bmgr1_w_expansions(
                oi_classifier, max_expanded_bits)

            expanded = oi_classifier.subset([])
            for i, exp in zip(lpm_indices, expansions):
                for entry in expand(oi_classifier[i], exp):
                    expanded.vmr.append(entry)

            if provide_non_expanded:
                non_expanded_subclassifiers.append(
                    oi_classifier.subset(lpm_indices).reorder(
                        _chain2bits(bitchain, oi_classifier.bit_width)))

            subclassifiers.append(
                expanded.reorder(_chain2bits(bitchain,
                                             oi_classifier.bit_width)))

        classifier = classifier.subset(
            set(range(len(classifier))) - set(oi_indices[i]
                                              for i in lpm_indices))

        p4t_native.log("OI decomposition has finished")

    if provide_non_expanded:
        return subclassifiers, classifier, non_expanded_subclassifiers
    else:
        return subclassifiers, classifier