Пример #1
0
def validate_isomorphisms(tmplt, world, candidates, unspec_cover):
    """ Validate that at least one isomorphism exists"""
    global n_iterations
    n_iterations += 1
    if len(unspec_cover) == 0:
        return validate_alldiff_solns(tmplt, world, candidates)

    unspec_idx = unspec_cover[0]
    unspec_cands = np.argwhere(candidates[unspec_idx]).flat

    for cand_idx in unspec_cands:
        # Make a copy to avoid messing up candidate sets during recursion
        candidates_copy = candidates.copy()
        candidates_copy[unspec_idx, :] = uclasm.one_hot(
            cand_idx, world.n_nodes)

        # rerun filters after picking an assignment for the next unspec node
        _, new_world, new_candidates = uclasm.run_filters(
            tmplt,
            world,
            candidates=candidates_copy,
            filters=uclasm.cheap_filters,
            init_changed_cands=uclasm.one_hot(unspec_idx, tmplt.n_nodes))

        # if any node has no cands due to the current assignment, skip
        if not new_candidates.any(axis=1).all():
            continue

        if validate_isomorphisms(tmplt, new_world, new_candidates,
                                 unspec_cover[1:]):
            return True
    return False
Пример #2
0
def process_fn(tmplt, world, result_queue=None, label=None, count_isomorphisms=False):
    result = {}
    result["label"] = label # For identifying results afterwards
    start_time = default_timer()
    tmplt, world, candidates = uclasm.run_filters(tmplt, world, candidates=tmplt.is_cand, filters=uclasm.cheap_filters, verbose=False)
    filter_time = default_timer()-start_time
    # print("Time taken for filters: {}".format(filter_time))
    # filter_times.append(filter_time)
    result["filter_time"] = filter_time

    # start_time = default_timer()
    # from filters.validation_filter import validation_filter
    # validation_filter(tmplt, world, candidates=candidates, in_signal_only=False,
    #       verbose=False)
    # print("Time taken for validation: {}".format(default_timer()-start_time))
    # validation_times += [default_timer()-start_time]
    # # tmplt.candidate_sets = {x: set(world.nodes[candidates[idx,:]]) for idx, x in enumerate(tmplt.nodes)}

    if count_isomorphisms:
        # # print("Starting isomorphism count")
        start_time = default_timer()
        count, n_iterations = uclasm.count_isomorphisms(tmplt, world, candidates=candidates, verbose=False, count_iterations=True)
        # print("Counted {} isomorphisms in {} seconds".format(count, default_timer()-start_time))
        iso_count_time = default_timer() - start_time
        # iso_counts += [count]
        # iso_count_times += [default_timer()-start_time]
        result["n_isomorphisms"] = count
        result["iso_count_time"] = iso_count_time
        result["has_iso"] = count > 0
    else:
        start_time = default_timer()
        from uclasm.counting.has_isomorphism import has_isomorphism
        has_iso, n_iterations = has_isomorphism(tmplt, world, candidates=candidates, verbose=False, count_iterations=True)
        # if has_iso:
        #     print("Has isomorphism")
        # else:
        #     print("No isomorphism")
        iso_check_time = default_timer() - start_time
        # print("Isomorphism checked in {} seconds".format(iso_check_time))
        # iso_check_times.append(iso_check_time)

        result["iso_check_time"] = iso_check_time
        result["has_iso"] = has_iso
    result["n_iterations"] = n_iterations

    if result_queue is not None:
        result_queue.put(result)
    else:
        return result
Пример #3
0
def validate_isomorphisms(tmplt, world, candidates, unspec_cover, marked,
                          in_signal_only, node_to_marked_col_idx):
    """ Validate that at least one isomorphism exists and unmark it """
    if len(unspec_cover) == 0:
        return validate_alldiff_solns(tmplt, world, candidates, marked,
                                      in_signal_only, node_to_marked_col_idx)

    unspec_idx = unspec_cover[0]
    unspec_cands = np.argwhere(candidates[unspec_idx]).flat

    # TODO: is this actually an effective heuristic? Compare with random order
    # Order unspec_cands to have marked nodes first
    unspec_cands = sorted(unspec_cands,
                          key=lambda cand_idx: marked[unspec_idx, cand_idx],
                          reverse=True)

    for cand_idx in unspec_cands:
        # Make a copy to avoid messing up candidate sets during recursion
        candidates_copy = candidates.copy()
        candidates_copy[unspec_idx, :] = uclasm.one_hot(
            cand_idx, world.n_nodes)

        # rerun filters after picking an assignment for the next unspec node
        _, new_world, new_candidates = uclasm.run_filters(
            tmplt,
            world,
            candidates=candidates_copy,
            filters=uclasm.cheap_filters,
            init_changed_cands=uclasm.one_hot(unspec_idx, tmplt.n_nodes))

        # if any node has no cands due to the current assignment, skip
        if not new_candidates.any(axis=1).all():
            continue

        if validate_isomorphisms(tmplt, new_world, new_candidates,
                                 unspec_cover[1:], marked, in_signal_only,
                                 node_to_marked_col_idx):
            marked_col_idx = node_to_marked_col_idx[world.nodes[cand_idx]]
            if in_signal_only:
                # Unmark all pairs for the found candidate
                marked[:, marked_col_idx] = False
            else:
                # Unmark the found pair
                marked[unspec_idx, marked_col_idx] = False
            return True
    return False
Пример #4
0
def has_isomorphism(tmplt,
                    world,
                    *,
                    candidates=None,
                    verbose=False,
                    count_iterations=False,
                    **kwargs):
    """
    Searches for an isomorphism and returns true if one is found, else returns false
    """
    global n_iterations
    n_iterations = 0
    if candidates is None:
        tmplt, world, candidates = uclasm.run_filters(
            tmplt,
            world,
            filters=uclasm.all_filters,
            candidates=np.ones((tmplt.n_nodes, world.n_nodes), dtype=np.bool),
            **kwargs)

    # TODO: only recompute unspec_cover when necessary or not at all
    # Get node cover for unspecified nodes
    cand_counts = candidates.sum(axis=1)
    unspec_subgraph = tmplt.subgraph(cand_counts > 1)
    unspec_cover = uclasm.get_node_cover(unspec_subgraph)
    unspec_cover = np.array(
        [tmplt.node_idxs[unspec_subgraph.nodes[idx]] for idx in unspec_cover],
        dtype=np.int)

    # TODO: pass arguments as keywords to avoid bugs when changes are made
    if validate_isomorphisms(tmplt, world, candidates, unspec_cover):
        if count_iterations:
            return True, n_iterations
        return True
    if count_iterations:
        return False, n_iterations
    return False
Пример #5
0
import uclasm

from load_data_combo import tmplt, world

tmplt, world, candidates = uclasm.run_filters(tmplt,
                                              world,
                                              filters=uclasm.all_filters,
                                              verbose=True)
n_isomorphisms = uclasm.count_isomorphisms(tmplt,
                                           world,
                                           candidates=candidates,
                                           verbose=False)

print("\nFound", n_isomorphisms, "isomorphisms")
Пример #6
0
        #                         link_types = ["R","C","S"]
        #                         update_node_candidates(tmplt, world,letter+str(row)+link_types[k], set(world_nodes[k*size*size+(digit-1)*size:k*size*size+(digit-1)*size+size]))
        #                         changed_nodes[tmplt.node_idxs[letter+str(row)+link_types[k]]] = True
        #         row += 1

        #        tmplt.summarize_candidate_sets()
        # print("Time to create world and template: {}".format(default_timer()-start_time))

        # tmplt.candidate_sets = {x: set(world.nodes[tmplt.is_cand[idx,:]]) for idx, x in enumerate(tmplt.nodes)}
        # display_sudoku2(tmplt, show_cands=False)

                start_time = default_timer()
                tmplt, world, candidates = uclasm.run_filters(
                    tmplt,
                    world,
                    candidates=tmplt.is_cand,
                    init_changed_cands=changed_nodes,
                    filters=uclasm.all_filters,
                    verbose=False)
                print("Time taken for filters: {}".format(default_timer() -
                                                          start_time))
                filter_times += [default_timer() - start_time]
                start_time = default_timer()
                from filters.validation_filter import validation_filter
                validation_filter(tmplt,
                                  world,
                                  candidates=candidates,
                                  in_signal_only=False,
                                  verbose=False)
                print("Time taken for validation: {}".format(default_timer() -
                                                             start_time))
Пример #7
0
def validation_filter(tmplt,
                      world,
                      *,
                      candidates=None,
                      in_signal_only=False,
                      verbose=False,
                      **kwargs):
    """
    This filter finds the minimum candidate set for each template node by
    identifying one isomorphism for each candidate-template node pair

    in_signal_only: Rather than checking pairs, if this option is True, only
     check that each candidate participates in at least one signal, ignoring
     which template node it corresponds to
    """
    if candidates is None:
        tmplt, world, candidates = uclasm.run_filters(
            tmplt,
            world,
            filters=uclasm.all_filters,
            candidates=np.ones((tmplt.n_nodes, world.n_nodes), dtype=np.bool),
            **kwargs)

    # Start by marking every current candidate-template node pair to be checked
    # A zero entry here means that we have already checked whether or not the
    # candidate corresponds to the template node in any signals.
    marked = candidates.copy()

    node_to_marked_col_idx = {
        node: idx
        for idx, node in enumerate(world.nodes)
    }

    while marked.any():
        if verbose:
            print(marked.sum(), "marks remaining")

        candidates_copy = candidates.copy()

        # TODO: only recompute unspec_cover when necessary or not at all
        # Get node cover for unspecified nodes
        cand_counts = candidates.sum(axis=1)
        unspec_subgraph = tmplt.subgraph(cand_counts > 1)
        unspec_cover = uclasm.get_node_cover(unspec_subgraph)
        unspec_cover = np.array([
            tmplt.node_idxs[unspec_subgraph.nodes[idx]] for idx in unspec_cover
        ],
                                dtype=np.int)

        # Find a marked template node idx and a cand to pair together

        # Pick any pair with a mark
        marked_tmplt_idx, marked_cand_idx = np.argwhere(marked)[0]

        # unspecified template nodes which have any marks
        marked_unspecs = marked[unspec_cover].any(axis=1)

        # If there is a node in the unspec cover with a mark, prioritize it
        if marked_unspecs.any():
            # Pick the first node in the unspec cover that has a mark
            marked_tmplt_idx = unspec_cover[marked_unspecs][0]

            # Set a candidate for the marked template node as the marked cand
            marked_cand_idx = np.argwhere(marked[marked_tmplt_idx])[0, 0]

        candidates_copy[marked_tmplt_idx, :] = uclasm.one_hot(
            marked_cand_idx, world.n_nodes)

        # TODO: pass arguments as keywords to avoid bugs when changes are made
        if not validate_isomorphisms(tmplt, world, candidates_copy,
                                     unspec_cover, marked, in_signal_only,
                                     node_to_marked_col_idx):
            # No valid isomorphisms: remove from is_cand
            candidates[marked_tmplt_idx, marked_cand_idx] = False
            # Unmark the pair that was checked
            marked[marked_tmplt_idx, marked_cand_idx] = False
            # TODO: run cheap filters to propagate change of candidates
            # TODO: reduce world to cands
        elif in_signal_only:
            # Unmark all pairs for the candidate that was found
            marked[:, marked_cand_idx] = False
        else:
            # Unmark the pair that was found
            marked[marked_tmplt_idx, marked_cand_idx] = False

    return tmplt, world, candidates
Пример #8
0
import sys
sys.path.append("..")

import uclasm

from load_data_combo import tmplt, world

uclasm.run_filters(tmplt, world, uclasm.all_filters, verbose=True)
n_isomorphisms = uclasm.count_isomorphisms(tmplt, world, verbose=False)

print("\nFound", n_isomorphisms, "isomorphisms")
Пример #9
0
def plot_barcharts(tmplt,
                   world,
                   results_dir,
                   data_name,
                   neighborhood=True,
                   elimination=True,
                   validation=False):
    """
    Plot (1) number of candidates of each template node (2) number of template
    nodes that each world node is the candidate of
    """
    filters = [uclasm.stats_filter]
    tmplt, world, candidates = uclasm.run_filters(tmplt,
                                                  world,
                                                  filters=filters,
                                                  verbose=False,
                                                  reduce_world=True)
    cands_stats = candidates.sum(axis=1)
    cinvs_stats = candidates.sum(axis=0)

    filters.append(uclasm.topology_filter)
    tmplt, world, candidates = uclasm.run_filters(tmplt,
                                                  world,
                                                  candidates=candidates,
                                                  filters=filters,
                                                  verbose=False,
                                                  reduce_world=True)
    cands_topo = candidates.sum(axis=1)
    cinvs_topo = candidates.sum(axis=0)

    if neighborhood:
        filters.append(uclasm.neighborhood_filter)
        tmplt, world, candidates = uclasm.run_filters(tmplt,
                                                      world,
                                                      candidates=candidates,
                                                      filters=filters,
                                                      verbose=False,
                                                      reduce_world=False)
        cands_nbhd = candidates.sum(axis=1)
        cinvs_nbhd = candidates.sum(axis=0)

    if elimination:
        tmplt, world, candidates = uclasm.run_filters(
            tmplt,
            world,
            candidates=candidates,
            filters=uclasm.all_filters,
            verbose=False,
            reduce_world=False)
        cands_elim = candidates.sum(axis=1)
        cinvs_elim = candidates.sum(axis=0)

    if validation:
        tmplt, world, candidates = validation_filter(tmplt,
                                                     world,
                                                     candidates=candidates,
                                                     verbose=False,
                                                     reduce_world=False)
        cands_valid = candidates.sum(axis=1)
        cinvs_valid = candidates.sum(axis=0)

    # Sort by # of candidates left after elim, topo, stats
    if validation:
        order_tmplt = sorted(range(len(tmplt.nodes)), \
            key=lambda idx: (cands_valid[idx], cands_elim[idx], cands_nbhd[idx],\
                            cands_topo[idx], cands_stats[idx]))

        order_world = sorted(range(len(world.nodes)), \
            key=lambda idx: (cinvs_valid[idx], cinvs_elim[idx], cinvs_nbhd[idx],\
                            cinvs_topo[idx], cinvs_stats[idx]))
    elif elimination:
        order_tmplt = sorted(range(len(tmplt.nodes)), \
            key=lambda idx: (cands_elim[idx], \
                            cands_topo[idx], cands_stats[idx]))

        order_world = sorted(range(len(world.nodes)), \
            key=lambda idx: (cinvs_elim[idx], \
                            cinvs_topo[idx], cinvs_stats[idx]))
    else:
        order_tmplt = sorted(range(len(tmplt.nodes)), \
            key=lambda idx: (cands_nbhd[idx], \
                            cands_topo[idx], cands_stats[idx]))

        order_world = sorted(range(len(world.nodes)), \
            key=lambda idx: (cinvs_nbhd[idx], \
                            cinvs_topo[idx], cinvs_stats[idx]))

    # Reorganize the candidates
    cands_stats = np.array([cands_stats[i] for i in order_tmplt])
    cands_topo = np.array([cands_topo[i] for i in order_tmplt])

    cinvs_stats = np.array([cinvs_stats[i] for i in order_world])
    cinvs_topo = np.array([cinvs_topo[i] for i in order_world])

    # Keep only the world nodes that are still candidates to at least one
    # tmplt node after topology filter
    world_to_keep = np.nonzero(cinvs_topo)[0]
    cinvs_stats = cinvs_stats[world_to_keep]
    cinvs_topo = cinvs_topo[world_to_keep]

    if neighborhood:
        cands_nbhd = np.array([cands_nbhd[i] for i in order_tmplt])
        cinvs_nbhd = np.array([cinvs_nbhd[i] for i in order_world])
        cinvs_nbhd = cinvs_nbhd[world_to_keep]

    if elimination:
        cands_elim = np.array([cands_elim[i] for i in order_tmplt])
        cinvs_elim = np.array([cinvs_elim[i] for i in order_world])
        cinvs_elim = cinvs_elim[world_to_keep]

    if validation:
        cands_valid = np.array([cands_valid[i] for i in order_tmplt])
        cinvs_valid = np.array([cinvs_valid[i] for i in order_world])
        cinvs_valid = cinvs_valid[world_to_keep]

    y1 = np.arange(len(tmplt.nodes))
    y2 = np.arange(len(world_to_keep))

    plt.rcParams.update({'font.size': 20})
    plt.rcParams["font.family"] = "DejaVu Serif"
    plt.rcParams['figure.figsize'] = (15, 12)

    _, color1, color2, color3, color4, color5 = sns.color_palette("Blues",
                                                                  n_colors=6)

    ax1 = plt.subplot(211)

    # Plot tmplt bars
    # plt.figure()
    plt.bar(y1, height=cands_stats, align='center', color=color1, \
                alpha=1, width=1, label='After Statistics')
    plt.bar(y1, height=cands_topo,  align='center', color=color2, \
                alpha=1, width=1, label='After Topology')
    if neighborhood:
        plt.bar(y1, height=cands_nbhd, align='center', color=color3, \
                    alpha=1, width=1, label='After Neighborhood')
    if elimination:
        plt.bar(y1, height=cands_elim, align='center', color=color4, \
                    alpha=1, width=1, label='After Elimination')
    if validation:
        plt.bar(y1, height=cands_valid, align='center', color=color5, \
                    alpha=1, width=1, label='After Validation')

    plt.yscale('log')
    plt.xlabel('Template Node No.', fontsize=20)
    plt.ylabel('Number of Candidates', fontsize=20)
    # plt.ylim(0, 2500)
    # plt.legend(loc='upper center', bbox_to_anchor=(0.5, 1.4), ncol=1, fancybox=True, shadow=True)
    # plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
    # plt.savefig('{}/{}_tmplt_bars_new.png'.format(results_dir, data_name), bbox_inches='tight')
    # plt.close()

    ax2 = plt.subplot(212)

    # Plot world bars
    # plt.figure()
    plt.bar(y2, height=cinvs_stats, align='center', color=color1, \
                alpha=1, width=1, label='After Statistics')
    plt.bar(y2, height=cinvs_topo, align='center',color=color2, \
                alpha=1, width=1, label='After Topology')
    if neighborhood:
        plt.bar(y2, height=cinvs_nbhd, align='center', color=color3, \
                    alpha=1, width=1, label='After Neighborhood')
    if elimination:
        plt.bar(y2, height=cinvs_elim, align='center', color=color4, \
                    alpha=1, width=1, label='After Elimination')
    if validation:
        plt.bar(y2, height=cinvs_valid, align='center', color=color5, \
                    alpha=1, width=1,label='After Validation')
    plt.xlabel('World Node No.', fontsize=20)
    plt.ylabel('Number of Template Nodes', fontsize=20)
    plt.legend(loc='upper center',
               bbox_to_anchor=(0.5, -0.2),
               fancybox=True,
               shadow=True,
               ncol=2)
    plt.ylim(0, 40)
    # plt.savefig('{}/{}_world_bars_new.png'.format(results_dir, data_name),bbox_inches='tight')
    plt.savefig('{}/{}_bars.png'.format(results_dir, data_name),
                bbox_inches='tight')
    plt.close()