9
votes

Optimiser les demandes cartésiennes avec des coûts affinés

J'ai une demande d'optimisation des coûts que je ne sais pas comment s'il y a la littérature sur. Il est un peu difficile à expliquer, je présente mes excuses à l'avance pour la durée de la question

Il y a un serveur J'accède qui fonctionne de cette façon. P>

  • une demande est faite sur les dossiers (r1, ...) rn et les champs (f1, ... fp) li>
  • vous ne pouvez demander le produit cartésien (r1, ..., rp) x (f1, ... fp) li>
  • Le coût (temps et argent) associé à une demande d'un tel est affines la taille de la demande: li> Ul>

    T ((r1, ..., rn) x (f1, ..., fp) = a + b * n * p code> p>

    sans perte de généralité (juste en normalisant), on peut supposer que b = 1 code> si le coût est: p>

    T ((r1, ..., rn) x (f1, ... fp)) = a + n * p code> p>

    • Il me suffit de demander un sous-ensemble de paires (r1, f (r1)), ... (rk, f (rk)) code>, une demande qui vient des utilisateurs. Mon programme agit comme un intermédiaire entre l'utilisateur et le serveur (ce qui est externe). J'ai beaucoup de demandes comme celui-ci qui viennent (des dizaines de milliers par jour). Li> Ul>

      Graphiquement, on peut le considérer comme une matrice nxp clairsemée, pour laquelle je veux couvrir les valeurs non nulles avec une sous-matrice rectangulaire: p>

      for each permutation on rows: (n!)
         for each permutation on columns: (p!)
             for each possible covering of the n x p matrix: (time unknown, but large...)
                 compute cost of the covering
      
      • le nombre de sous-matrices étant maintenu raisonnable en raison du coût constant li>
      • tous les 'x' doit se situer dans une sous-matrice li>
      • la superficie totale couverte ne doit pas être trop importante en raison du coût linéaire li> Ul>

        Je nommerai g le coefficient faible densité de mon problème (nombre de paires nécessaires sur les paires possibles au total, g = k / (n * p) code>. Je sais que le coefficient a code> p>

        Il y a quelques observations évidentes: p>

        • si a est petit, la meilleure solution consiste à demander de manière indépendante chaque paire (fiche, sur le terrain), et le coût total est la suivante: k * (a + 1) = g * n * p * (a + 1 ) code> li>
        • si un est grande, la meilleure solution est de demander l'ensemble du produit cartésien, et le coût total est: a + n * p code> li>
        • la seconde solution est préférable dès g> g_min = 1 / (a ​​+ 1) * (1 + 1 / (n * p)) code> li>
        • bien sûr les commandes dans les produits cartésiens ne sont pas importants, donc je peux transposer les lignes et les colonnes de ma matrice pour le rendre plus facilement couvrable, par exemple: li> Ul>
             f1 f3 f2
          r1  x  x
          r3  x  x
          r2       x
          


4 commentaires

Vous avez un oracle qui vous dit lequel (la rangée, le col) est vide gratuitement?


Vous pouvez nommer les ensembles de lignes et de champs explicitement, c'est-à-dire que vous n'avez pas à spécifier un rectangle contigu dans un système de coordonnées fixes (des permutations de rangées et de cols)?


Re: Ma première question, la réponse est oui, si je comprends correctement les "demandes provenant des utilisateurs".


La réponse à votre deuxième question est également oui. S'il y a une permutation des rangées et des colonnes qui donne un trottoir moins rare, il est généralement meilleur (et je n'ai pas compris votre commentaire sur Artelius, répondit, désolé. Je suis limité à des rectangles contigus sur des permutations de lignes et de colonnes).


6 Réponses :


1
votes

Je suis sûr qu'il y a un très bon algorithme pour cela quelque part, mais voici mes propres idées intuitives:

  1. Approche à quelques rectangles:

    • Déterminez une taille rectangle "grossièrement optimale" basée sur A .
    • Placez ces rectangles (peut-être au hasard) sur vos points requis, jusqu'à ce que tous les points soient couverts.
    • Prenez maintenant chaque rectangle et rétrécissez-le autant que possible sans "perdre" des points de données.
    • Trouvez des rectangles proches les uns des autres et décidez si la combinaison d'eux serait moins chère que de les garder séparément.
    • grandir

      • Commencez avec chaque point dans son propre rectangle de 1x1.
      • localiser tous les rectangles dans n lignes / colonnes (où N peut être basé sur A ); Voyez si vous pouvez les combiner dans un rectangle sans frais (ou coût négatif: D).
      • répéter.
      • rétrécir

        • Commencez avec un gros rectangle, qui couvre tous les points.
        • Recherchez un sous-rectangle qui partage une paire de côtés avec le grand, mais contient très peu de points.
        • Coupez-le du grand, produisant deux plus petits rectangles.
        • répéter.
        • Quad

          • Divisez le plan en 4 rectangles. Pour chacun d'entre eux, voyez si vous obtenez un meilleur coût en recrutant davantage ou en incluant simplement le rectangle entier.
          • Prenez maintenant vos rectangles et voyez si vous pouvez fusionner l'un d'entre eux avec peu / pas de coût. \

            Aussi: garder à l'esprit qu'il sera parfois préférable d'avoir deux rectangles superposés d'un grand rectangle qui est un superset d'entre eux. Par exemple. le cas lorsque deux rectangles se chevauchent dans un coin.


3 commentaires

Vous n'êtes pas limité aux rectangles.


@ Wrang-Wrang: Oui je suis. @ Artelius, oui, cela est vrai qu'il est peut-être préférable d'avoir des rectangles qui se chevauchent que ceux strictement non émergents. Je teste actuellement une version modifiée de votre solution "Grow". Je démarre un rectangle de 1x1, puis je fusionne les deux rectangles et répétez les deux rectangles moins coûteux (peu coûteux). Il donne une liste linéaire de clusterings sur lesquels je prends le coût minimum dans cette liste. Mais le problème réel n'est pas ici, mais dans les transpositions, je peux faire sur les rangées et les colonnes, ce qui rend la combinatoire exploser (n! * P!, Ne pas comptabiliser la symétrie)


Ah, donc r1, ..., rn ne doit pas avoir à être consécutif? Je pense que ma tête va exploser.



0
votes

J'envisageais les n enregistrements (lignes) et P champs (COLS) mentionnés dans la demande de l'utilisateur défini sous forme de n points dans l'espace de la dimension p-dimensionnelle ({0,1} ^ p) avec la coordonnée qui étant 1 iff a un X, et Identifiez une hiérarchie de clusters , avec le cluster plus grossier à la racine, y compris tous Le X. Pour chaque nœud de la hiérarchie de la clustering, tenez compte du produit qui couvre toutes les colonnes nécessaires (il s'agit de lignes (n'importe quel sous-node) X cols (n'importe quel sous-node)). Ensuite, décidez de l'autre que de fusionner les couvre-enfants (payant pour toute la couverture), ou de les conserver en tant que demandes séparées. (Les revêtements ne sont pas des colonnes contiguës, mais exactement celles nécessaires; c'est-à-dire penser à un vecteur de bit)

Je suis d'accord avec Artelius qui se chevauchent des demandes de produit pourrait être moins chère; Mon approche hiérarchique nécessiterait une amélioration pour incorporer cela.


0 commentaires

0
votes

Étant donné que vos valeurs sont rares, car de nombreux utilisateurs demandent des valeurs similaires? La mise en cache dans votre application est-elle une option? Les demandes pourraient être indexées par un hachage qui correspond à la position (x, y), de sorte que vous puissiez facilement identifier les ensembles mis en cache qui tombent dans la zone correcte de la grille. Stocker les ensembles cachés dans un arbre, par exemple, vous permettrait de trouver des sous-ensembles mis en cache minimaux qui couvrent la gamme de demandes très rapidement. Vous pouvez ensuite faire une recherche linéaire sur le sous-ensemble, qui est petit.


1 commentaires

Bonjour, nous mettons déjà en cache les résultats, bien sûr. Le vrai problème est que nous ne savons pas vraiment comment faire expirer la demande. Ainsi, pour des activités critiques, les systèmes demandeurs ont la possibilité de contourner le cache de certaines valeurs (c'est en fait l'une des causes de la pâte à la portée de la demande).



1
votes

OK, ma compréhension de la question a changé. Nouvelles idées:

  • stocke chaque ligne comme une longue chaîne de bits. Et paires de cordes de bits ensemble, essayant de trouver des paires qui optimisent le nombre de 1 bits. Cultivez ces paires dans des groupes plus grands (trier et essayer de faire correspondre les très gros les uns avec les autres). Ensuite, construisez une demande qui va frapper le plus grand groupe, puis oublier toutes ces bits. Répétez jusqu'à ce que tout soit fait. Peut-être passer de lignes aux colonnes parfois.

  • Recherchez toutes les lignes / colonnes à zéro ou quelques points, points. "Supprimer"-les temporairement. Maintenant, vous regardez ce qui serait couvert par une demande qui les laisse. Maintenant peut-être appliquer l'une des autres techniques et traiter les rangées / cols ignorés par la suite. Une autre façon de penser à cela est la suivante: gérer d'abord les points plus denseurs, puis passer à des pelousser.


0 commentaires

5
votes

Sélection des sous-marines pour couvrir les valeurs demandées est une forme de Ensemble de problème de couverture et Par conséquent, NP complète. Votre problème ajoute à ce problème déjà dur que les coûts des ensembles diffèrent.

que vous autorisez à permuter les lignes et les colonnes n'est pas un problème si gros, car vous pouvez simplement envisager des soumissions déconnectées. En ligne une, colonnes de quatre à sept et cinq rangées cinq, les colonnes quatre deux sept sont un ensemble valide car vous pouvez simplement échanger la ligne deux et la rangée cinq et obtenir la rangée de la sous-chaîne connectée une, la colonne quatre à la colonne deux, la colonne sept. Bien sûr, cela ajoutera des contraintes - tous les ensembles ne sont pas valables sous toutes les permutations - mais je ne pense pas que ce soit le plus gros problème.

L'article Wikipedia donne les résultats de l'inapproximabilité que le problème ne peut pas être résolu en temps polynôme, puis avec un facteur 0.5 * log2 (n) n est le nombre de ensembles. Dans votre cas, 2 ^ (n * p) est une limite supérieure (assez pessimiste) pour le nombre d'ensembles et de rendements que vous ne pouvez trouver qu'une solution jusqu'à un facteur de 0.5 * N * P en temps polynomial (en plus de n = np et ignorant les coûts variables).

Une liaison inférieure optimiste pour le nombre d'ensembles ignorant les permutations des lignes et des colonnes est 0.5 * N ^ 2 * P ^ 2 donnant un meilleur facteur de log2 (n) + log2 (P) - 0.5 . En conséquence, vous ne pouvez vous attendre qu'à trouver une solution dans votre pire cas de n = 1000 et p = 200 jusqu'à un facteur d'environ 17 Dans le cas optimiste et jusqu'à un facteur de 100.000 dans le cas pessimiste (ignorant toujours les coûts variables).

Donc, le meilleur que vous puissiez faire est d'utiliser un algorithme heuristique (l'article de Wikipedia mentionne un algorithme gourmandais presque optimal) et accepter qu'il y aura du cas où l'algorithme effectue (très) mauvais. Ou vous allez dans l'autre sens et utilisez un algorithme d'optimisation et essayez de trouver une bonne solution utiliser plus de temps. Dans ce cas, je suggérerais d'essayer d'utiliser a * Recherche .


1 commentaires

Merci pour la réponse. Je suis assez conscient que la solution est dure NP, mais je cherche une solution qui fonctionnerait bien dans la pratique. Aussi, après une étude minutieuse, je pense que la formulation de couverture définie n'est pas triviale car 1) la fonction de coût est très particulière 2) les contraintes sont également. Il est temps de commencer une prime!



0
votes

Je travaille un peu dessus et voici une algorithme de brise de symétrie évidente, o (n ^ 3), et des enregistrements et des champs sont traités séparément) dans un pseudo-code de type Python.

L'idée est trivial: nous commençons par essayer une demande par enregistrement, et nous faisons la fusion la plus méritée jusqu'à ce qu'il ne reste plus rien de digne de fusionner. Cet algo a l'inconvénient évident qu'il n'autorise pas les demandes qui se chevauchent, mais je m'attends à ce qu'elle fonctionne assez bien sur l'affaire réelle (avec le + n * (p ^ b) + c * n * p * (1 - g) fonction de coût): xxx

ceci est O (n3 * p) car:

  • Après l'initialisation, nous commençons par n demandes
  • Le pendant La boucle supprime exactement une demande de la piscine à chaque itération.
  • le pour boucle iterate sur le ( NI ^ 2 - NI ) / 2 paires de demandes distinctes, avec NI passant de n à un dans le pire des cas (lorsque nous fusionnerons tout dans une grande demande).

    1. Quelqu'un peut-il m'aider à pointer les très mauvais cas de l'algorithme. Cela sonne-t-il raisonnable d'utiliser celui-ci?
    2. c'est O (n ^ 3) qui est trop coûteux pour les grandes intrants. Toute idée d'optimisation?

      Merci d'avance!


0 commentaires