12
votes

Intersection efficace Set - Décidez si l'intersection est plus grande que k

Je suis confronté à un problème où je dois calculer des intersections entre toutes les paires d'une collection d'ensembles. Aucun des ensembles n'est plus petit qu'une petite constante k , et je ne suis intéressé que si deux ensembles ont une intersection plus grande que les éléments k -1 ou non. Je n'ai pas besoin des intersections réelles ni la taille exacte, seulement s'il est plus grand que k -1 ou non. Y a-t-il une astuce de pré-traitement intelligente ou un algorithme d'intersection Set Set soie que je pourrais utiliser pour accélérer les choses?

Plus d'informations pouvant être utiles pour répondre à la question:

  • Les ensembles représentent des cliques maximaux dans un graphe large, non dirigé et clairsemé. Le nombre d'ensembles peut être de l'ordre des dizaines de milliers ou plus, mais la plupart des ensembles sont susceptibles d'être petits.
  • Les ensembles sont déjà triés Les membres de chaque ensemble sont en ordre croissant. Efficacement, ils sont des listes de tri - je les reçois de cette façon d'une bibliothèque sous-jacente pour la recherche de clique maximale.
  • Rien n'est connu sur la distribution d'éléments dans les ensembles (c'est-à-dire qu'ils soient dans des touffes serrées ou non).
  • La plupart des intersections définies sont susceptibles d'être vides. La solution idéale serait donc une structure de données intelligente qui m'aide à réduire le nombre d'intersections définies que je dois apporter.

8 commentaires

Le contenu de chaque ensemble est-il essentiellement aléatoire? Sinon, vous pourriez peut-être commander les ensembles à gauche par leur plus grand élément et les ensembles à droite par leur moins, évitant ainsi la prise en compte de nombreuses intersections vides. Cela fonctionnera très bien si la plupart des ensembles contiennent une touffe de valeurs à proximité et très mal si la plupart des ensembles contiennent à la fois l'élément minimum et maximum possible ...


Ermmm ... peut-être que cela n'était peut-être pas clair de la question; Il n'y a pas de côté «gauche» ou «à droite», j'ai une seule collection de jeux uniquement. Les ensembles sont en réalité des cliques maximaux de sommets dans un graphique et je cherche des paires de cliques ayant une intersection d'au moins k sommets.


Lors de la comparaison de deux ensembles, faites-vous référence arbitrairement à l'une d'elles comme la «gauche» et l'autre comme le «droit».


@steve Jessop , vous pouvez poster votre commentaire comme réponse - c'est bon si les ensembles sont petits. Une autre chose que je pouvais penser est un définir la mise en œuvre basée sur un tableau commandé. Il peut avoir un haskcommon (définir autre, INT K) Méthode qui comporte les éléments et quitte tôt, si le résultat est clair avant la fin de l'itération.


@Steve Jessop: Je vous encourage également à poster votre solution comme réponse, notamment parce qu'il y a une prime ouverte sur cette question maintenant. Ce que tu as écrit m'a donné une idée; Je trouverai les éléments minimum et maximum de chaque jeu avant de calculer les intersections et les utiliser pour renflouer tôt si les deux ensembles étant considérés sont disjoints.


Qu'entendez-vous par «les ensembles sont déjà triés»? Vous voulez dire qu'il est possible d'énumérer les ensembles et vous avez trié ces énumérations ou voulez-vous dire que les membres définis peuvent être énumérées et vous avez trié chacun de tous les membres des ensembles? Quel genre d'énumération utilisez-vous?


J'ai triché les membres de chaque ensemble de telle sorte qu'ils sont en ordre croissant. Essentiellement, chaque ensemble peut être traité comme une liste triée et il est possible d'intersecter l'un des deux ensembles de temps linéaire à l'aide de l'algorithme d'intersection naïf pour les séquences triées.


Merci pour toutes les réponses; Comme la date limite de la générosité s'approche rapidement, j'ai décidé d'attribuer la prime à celle qui s'est avérée être la plus rapide des graphiques que j'ai au moins parmi mes implémentations actuelles. Je vais probablement écrire mes expériences sous la forme d'un poteau de blog dans les prochains jours et postez l'URL ici.


4 Réponses :


5
votes

Une optimisation possible, qui est plus efficace, plus la gamme de valeurs contenues dans chaque ensemble:

  • Créez une liste de tous les ensembles, triés par leur élément kth-plus grand (c'est facile à trouver, car vous avez déjà chacun ensemble avec ses éléments dans l'ordre). Appelez cette liste l.
  • Pour les deux ensembles A et B, leur intersection ne peut pas avoir autant que k éléments de ks si l'élément kth-plus grand de A est inférieur au moindre élément de b.
  • Donc, pour chaque ensemble à son tour, calculez son intersection uniquement avec les ensembles de la partie correspondante de L.

    Vous pouvez utiliser le même fait pour sortir tôt du calcul de l'intersection de deux ensembles - s'il n'y a que des éléments N-1 laissés à comparer dans l'un des ensembles et l'intersection contient jusqu'à présent sur la plupart des éléments KN, puis arrêter. La procédure ci-dessus est simplement cette règle appliquée à tous les ensembles de L à la fois, avec N = K, au point où nous examinons le moins d'élément de l'ensemble B et le plus grand élément de A.


1 commentaires

Celui-ci fonctionne vraiment bien; J'ai réussi à appuyer sur la mise en œuvre non si naïf des miennes de 7,61s (pour 20000 cliques) à 5.8s; Ces temps sont les meilleurs de trois essais chacun. Je suis en train d'enquêter sur les autres solutions proposées, mais cela est vraiment prometteur (et simple).



5
votes

Considérez un mappage avec tous les ensembles de taille K comme clés et valeurs correspondantes des listes de tous les ensembles de votre collection qui contiennent la clé comme un sous-ensemble. Compte tenu de cette mappage, vous n'avez pas besoin d'effectuer des tests d'intersection: Pour chaque touche, toutes les paires d'ensembles de la liste auront une intersection de la taille au moins k. Cette approche peut produire la même paire d'ensembles plus d'une fois, de sorte que cela devra être vérifié.

La cartographie est suffisamment facile pour calculer. Pour chaque ensemble dans la collection, calculez tous les sous-ensembles Taille-K et appendez l'original défini sur la liste pour cet ensemble de touches. Mais est-ce réellement plus rapide? En général, non. La performance de cette approche dépendra de la distribution des tailles des ensembles de la collection et de la valeur de k. Avec D éléments distincts dans les ensembles, vous pourriez avoir autant que D choisissez K Keys, qui peut être très grande.

Cependant, l'idée de base est utilisable pour réduire le nombre d'intersections. Au lieu d'utiliser des ensembles de taille K, utilisez des plus petits de la taille fixe Q en tant que touches. Les valeurs sont à nouveau des listes de tous les ensembles qui ont la clé en tant que sous-ensemble. Maintenant, testez chaque paire d'ensembles de la liste pour l'intersection. Ainsi, avec q = 1, vous ne testez que ces paires d'ensembles qui ont au moins un élément en commun, avec q = 2, vous ne teste que ces paires d'ensembles qui ont au moins deux éléments en commun, etc. La valeur optimale pour Q dépendra de la distribution de tailles des ensembles, je pense.

Pour les ensembles en question, un bon choix peut être Q = 2. Les clés sont alors juste des bords du graphique, donnant une taille prévisible à la cartographie. Étant donné que la plupart des ensembles devraient être disjoints, Q = 2 devrait éliminer de nombreuses comparaisons sans trop de frais généraux supplémentaires.


1 commentaires

Enfin, j'ai eu un peu de temps pour mettre en œuvre et tester cette version également, et il s'est avéré être le plus rapide de toutes les solutions qui ont été postées ici jusqu'à présent. Pour 20k Cliques, il était presque 10 fois plus rapidement que le finaliste.



2
votes

La stratégie suivante devrait être assez efficace. J'ai utilisé des variantes de ceci pour intersecter des séquences ascendantes à plusieurs reprises.

Je suppose d'abord que vous avez une sorte de queue prioritaire em> disponible (sinon, rouler votre propre tas est assez facile. ). Et une recherche de clé / valeur rapide (BTREE, hachage, peu importe). P>

avec qui dit, voici pseudocode pour un algorithme qui devrait faire ce que vous voulez de manière assez efficace. P>

# Initial setup
sets = array of all sets
intersection_count = key/value lookup with keys = (set_pos, set_pos) and values are counts.
p_queue = priority queue whose elements are (set[0], 0, set_pos), organized by set[0]

# helper function
def process_intersections(current_sets):
    for all pairs of current_sets:
        if pair in intersection_count:
            intersection_count[pair] += 1
        else:
            intersection_count[pair] = 1

# Find all intersections
current_sets = []
last_element = first element of first thing in p_queue
while p_queue is not empty:
    (element, ind, set_pos) = get top element from p_queue
    if element != last_element:
        process_intersections(current_sets)
        last_element = element
        current_sets = []
    current_sets.append(set_pos)
    ind += 1
    if ind < len(sets[set_pos]):
        add (sets[set_pos][ind], ind, set_pos) to p_queue
# Don't forget the last one!
process_intersections(current_sets)

final answer = []
for (pair, count) in intersection_count.iteritems():
    if k-1 < count:
        final_answer.append(pair)


1 commentaires

J'avais évoqué cela deux fois si je pouvais; J'ai réussi à mettre en œuvre cet hier en C ++ et c'est vraiment rapide. Je posterai quelques résultats de référence en un jour ou plus.



0
votes

Et si vous utilisiez un sous-ensemble prédictif en tant que préqualificateur. Prétraitement, mais utilisez une intersection sous-ensemble comme condition de seuil. Si l'intersection des sous-ensembles> N% complète ensuite l'intersection, sinon abandonnez. n devient alors l'inverse de votre niveau de confort avec la perspective d'un faux positif.

Vous pouvez également trier par les intersections de sous-ensemble (M) calculées précédemment et commencer à exécuter l'intersection complète commandée par M décroissant. Donc, vraisemblablement, la majorité de vos intersections de M les plus hautes seraient probablement franchiront probablement votre seuil K sur le sous-ensemble complet et que le seuil de frappe de votre K pourrait diminuer continuellement.

Cela commence vraiment à traiter le problème comme NP-complet.


0 commentaires