C structure de données pour imiter de C#List<List<int>>?
Je suis à la recherche de refactoriser une méthode c# dans une fonction c dans une tentative de gagner un peu de vitesse, et ensuite appeler la dll c en c# pour permettre à mon programme pour utiliser la fonctionnalité.
Actuellement la méthode c# prend une liste d'entiers et qui renvoie une liste de listes de nombres entiers. La méthode calculé la puissance des entiers donc, une entrée de 3 ints d'obtenir le résultat suivant (à ce stade, les valeurs de l'ints est pas importante car elle est utilisée en interne d'une valeur de pondération)
1
2
3
1,2
1,3
2,3
1,2,3
Où chaque ligne représente une liste d'entiers. La sortie indique l'index (avec un décalage de 1) de la première liste, non pas la valeur. Donc 1,2 indique que l'élément à l'indice 0 et 1 sont un élément de la puissance.
Je suis pas familier avec le c, donc ce sont mes meilleures options pour les structures de données qui va permettre à la c# pour accéder aux données renvoyées?
Merci d'avance
Mise à jour
Merci à tous pour vos commentaires jusqu'à présent. Ici, c'est un peu un arrière-plan à la nature du problème.
La méthode itérative pour le calcul de la puissance d'un ensemble est assez simple. Deux boucles et un peu de manipulation de bits est tout là est à lui vraiment. Il a juste appelé..beaucoup (en fait des milliards de fois, si la taille de l'ensemble est assez grand).
Thoughs autour de l'aide de c (c++ comme les gens l'ont souligné) sont qu'il donne plus de portée pour l'optimisation des performances. Un port direct ne peuvent pas offrir toute augmentation, mais elle ouvre la voie pour plus porté sur les méthodes pour obtenir un peu plus de vitesse hors de lui. Même une petite augmentation par itération équivaudrait à une augmentation mesurable.
Mon idée était de port direct version et ensuite travailler pour l'augmenter. Et puis à refactoriser au fil du temps (avec l'aide de tout le monde ici, DONC).
Mise à jour 2
Juste un autre point de jalf.com, je n'ai pas à utiliser la liste ou equivelent. Si il ya une meilleure façon, alors je suis ouvert aux suggestions. La seule raison pour laquelle la liste a été que chaque ensemble de résultats n'est pas de la même taille.
Le code pour l'instant...
public List<List<int>> powerset(List<int> currentGroupList)
{
_currentGroupList = currentGroupList;
int max;
int count;
//Count the objects in the group
count = _currentGroupList.Count;
max = (int)Math.Pow(2, count);
//outer loop
for (int i = 0; i < max; i++)
{
_currentSet = new List<int>();
//inner loop
for (int j = 0; j < count; j++)
{
if ((i & (1 << j)) == 0)
{
_currentSetList.Add(_currentGroupList.ElementAt(j));
}
}
outputList.Add(_currentSetList);
}
return outputList;
}
Comme vous pouvez le voir, pas beaucoup à elle. Il va rond et rond beaucoup!
J'accepte que la création et la construction de listes peut ne pas être le moyen le plus efficace, mais j'ai besoin d'un moyen de fournir les résultats dans une manière gérable.
Mise à jour 2
Merci pour tous les commentaires et la mise en œuvre des travaux. Juste pour clarifier quelques points soulevés: je n'ai pas besoin de la sortie pour être en "ordre naturel", et aussi je ne suis pas intéressé par l'ensemble vide est retournée.
hughdbrown de la mise en œuvre est intesting mais je pense que j'ai besoin de stocker les résultats (ou au moins une partie d'entre eux) à un certain point. Cela ressemble à de la mémoire limitiations appliquera à long avant d'exécuter le temps devient un réel problème.
En partie à cause de cela, je pense que je peux m'en sortir avec l'aide octets au lieu de nombres entiers, de donner plus de potentiel de stockage.
La véritable question est donc la suivante: Avons-nous atteint la vitesse maximale pour cette calcualtion en C#? L'option de code non managé fournir plus de portée. Je sais que dans de nombreux égards, la réponse est futile, car même si nous havled le temps de courir, il ne ferait que permettre un supplément de valeurs dans le jeu original.
- int** une liste à une liste de int.
- non, il a juste des points à un pointeur vers un int. Le montant de la simplification conduira à de nombreuses heures de débogage de la douleur pour nos chers jxh00u
- Cela dépend vraiment de ce que vous faites avec elle 🙂
- L'interopérabilité va tuer tous les gains de performance. Afficher votre C# et demander un meilleur algorithme, ou peu sûres de manipulation du pointeur conseils.
- Wouldnt l'interopérabilité ralentir seulement se produire que lorsque l'appel a été fait?
- Il sera toujours plus facile, plus sûre et plus facile à maintenir si vous optimisé le C#.
- Re: à l'aide d'octets au lieu de nombres entiers, de donner plus de potentiel de stockage des Entiers de quatre fois la taille d'octets. Cela signifie que vous pourriez gérer un powerset avec plus de deux éléments. Est-ce vraiment utile? À l'aide de taux de retour pour ne conserver qu'un seul set en mémoire donne un véritable coup de fouet.
- Re: je pense que j'ai besoin de stocker les résultats (ou au moins une partie d'entre eux), Vous allez déterminer au moment de l'exécution que certains sous-ensemble est intéressant/utile? Pouvez-vous nous dire quel type d'application que vous construisez? Et combien d'éléments dont vous avez besoin pour powerset à la fois?
- Je suppose que je suis en train d'essayer de trouver la limite théorique de choses que je pourrais powerset. L'application powerset certains objecs qui peuvent être regroupés pour fournir une sauvegarde (c'est à dire faire deux choses en même temps est mieux que de faire les deux choses independtntly). Je sais que c'est une implémentation naïve...
- suite...et devinez ce qu'une certaine dynamique ou heuristical méthode pourrait se rapprocher pour moins d'effort. Les valeurs dans l'entrée sera un "coût". En additionnant les valeurs de chaque powerset de retour (ou de conserver un total en cours d'exécution dans la boucle) permettra de déterminer si l'ensemble est "valable". Je suis d'accord que le rendement de retour est utile.
Vous devez vous connecter pour publier un commentaire.
Ce retourne un ensemble de powerset à la fois. Il est basé sur le code python ici. Il travaille pour powersets de plus de 32 éléments. Si vous avez besoin de moins de 32, vous pouvez modifier long int. Il est assez vite, plus vite que mon algorithme précédent et plus rapide que (mon modifiés pour utiliser les taux de retour en version) P Daddy code.
Vous pouvez télécharger toutes les versions plus rapide, j'ai testé ici.
Je pense vraiment que l'utilisation de taux de retour est le changement qui rend le calcul de grand powersets possible. L'allocation de grandes quantités de mémoire initial d'exécution augmente de façon spectaculaire et les causes des algorithmes à l'échec par manque de mémoire très tôt. Affiche originale devriez comprendre comment de nombreux ensembles d'un ensemble des parties qu'il faut à la fois. Détenant la totalité d'entre eux n'est pas vraiment une option >24 éléments.
Aussi, assurez-vous que le passage à la C/C++ est vraiment ce que vous devez faire pour la vitesse, pour commencer. Instrument de l'original de la méthode C# (autonome, exécutée par le biais de tests unitaires), instrument de la nouvelle C/C++ méthode (encore une fois, autonome via des tests unitaires) et de voir ce que le monde réel différence.
La raison pour laquelle je aborder cette question, c'est que je crains qu'il ne peut être un pyrhhic victoire -- à l'aide de Smokey Bacon conseils, vous obtenez votre liste de classe, vous êtes dans le "plus rapide" C++, mais il y a toujours un coût pour l'appelant que la DLL: Rebondir hors de la durée de P/Invoke ou COM interop porte une somme assez importante sur les performances.
Être sûr que vous êtes l'obtention de votre "argent" de ce saut avant de le faire.
Mise à jour basé sur l'OP de la mise à Jour
Si vous êtes à l'appel de cette boucle, vous devez absolument vous assurer que la totalité de la boucle logique est encapsulé dans un seul appel d'interopérabilité -- dans le cas contraire les frais généraux de triage (comme d'autres ici l'ont mentionné) va certainement vous tuer.
Je pense que, compte tenu de la description du problème, que le problème n'est pas que C#/.NET est "plus lent" que C, mais il est plus probable que le code doit être optimisé. Comme une autre affiche ici mentionnés, vous pouvez utiliser les pointeurs en C# sérieusement d'augmenter les performances dans ce genre de boucle, sans la nécessité pour la sérialisation. Je regarde pour la première, avant de sauter dans un complexe interop monde, pour ce scénario.
Si vous êtes à la recherche d'utiliser le C pour un gain de performance, le plus probable que vous envisagez de le faire par le biais de l'utilisation de pointeurs. C# ne permet l'utilisation des pointeurs, en utilisant le mot-clé unsafe. Avez-vous pensé à cela?
Également comment allez-vous appeler ce code.. qu'il sera appelé souvent (par exemple, dans une boucle?) Si oui, le fait d'insérer les données avant et arrière peuvent plus que compenser les gains de performance.
Suivi
Prendre un coup d'oeil à Code natif sans sacrifier .Performance NETTE pour certains interop options. Il existe des moyens pour l'interopérabilité sans trop de perte de performance, mais ceux interops ne peut se faire avec le plus simple des types de données.
Si j'ai toujours pense que vous devriez enquêter sur la vitesse de votre code à l'aide de droites .NET.
Suivi 2
Aussi, je suggère que si vous avez votre coeur sur un mélange de code natif et du code managé, que vous créez votre bibliothèque à l'aide de c++/cli. Ci-dessous est un exemple simple. Notez que je ne suis pas un c++/cli gars, et ce code ne fait rien d'utile...ses juste pour but de montrer comment vous pouvez facilement mélanger de code natif et géré.
Ce qui vous fait penser que vous allez gagner de la vitesse en appelant le code C? C n'est pas comme par magie plus rapide que le C#. Il peut être, bien sûr, mais il peut aussi facilement être plus lent (et buggier). Surtout quand vous facteur dans le p/invoke appels en code natif, il est loin d'être certain que cette approche permettra d'accélérer quoi que ce soit.
En tout cas, C de ne pas avoir quelque chose comme la Liste. Il a cru les tableaux et les pointeurs (et on pourrait dire que int** est plus ou moins l'équivalent), mais vous êtes probablement mieux d'utiliser C++, qui n'ont d'équivalent structures de données. En particulier, std::vector.
Il n'y a pas de moyens simples pour exposer ces données, C#, cependant, car il sera dispersé assez bien au hasard (chaque liste est un pointeur vers certains de mémoire allouée dynamiquement quelque part)
Je soupçonne cependant, la plus grande amélioration de la performance provient de l'amélioration de l'algorithme en C#.
Edit:
Je peux voir plusieurs choses dans votre algorithme qui semblent fonctionner de manière optimale. La construction d'une liste de listes n'est pas gratuit. Peut-être vous pouvez créer une liste unique et l'utilisation des positions différentes pour représenter chaque sous-liste. Ou peut-être à l'aide du rendement de retour " et IEnumerable au lieu de construire explicitement des listes pourrait être plus rapide.
Avez-vous profilé votre code, où le temps est dépensé?
Je vais aussi mettre un vote pour le réglage de votre C#, en particulier en allant de code "potentiellement dangereux" et de perdre ce qui pourrait être beaucoup de vérification de limites de surcharge.
Même si c'est "dangereux", il n'est pas moins " sûr " que le C/C++, et c'est beaucoup plus facile pour obtenir le droit.
Ci-dessous est un C# algorithme qui devrait être beaucoup plus rapide (et d'utiliser moins de mémoire) que l'algorithme que vous avez posté. Il n'utilise pas le soigné binaire astuce vôtre utilise, et comme un résultat, le code est un bon peu plus longtemps. Il a un peu plus de
for
boucles que la vôtre, et qui peut prendre une heure ou deux de marcher à travers elle avec le débogueur entièrement grok il. Mais c'est en fait une approche la plus simple, une fois que vous comprenez ce qu'il fait.Comme un bonus, les jeux sont plus "naturelles" de l'ordre. Il serait de retour des sous-ensembles de l'ensemble {1 2 3} dans le même ordre que vous avez indiquée dans votre question. Ce n'était pas un accent, mais est un effet secondaire de l'algorithme utilisé.
Dans mes tests, j'ai trouvé cet algorithme soit environ 4 fois plus rapide que l'algorithme que vous avez posté pour un grand jeu de 22 articles (qui était aussi grand que je pouvais aller sur ma machine sans trop de disque-volée de biaiser les résultats trop). Un run de la vôtre a pris environ 15,5 secondes, et le mien a pris environ 3,6 secondes.
Pour les petites listes, la différence est moins prononcée. Pour un ensemble de seulement 10 points, le vôtre a couru 10 000 fois environ 7,8 secondes, et le mien a pris environ 3,2 secondes. Pour les ensembles avec 5 ou moins d'éléments, ils ont a peu près le même temps. Avec un nombre d'itérations, la vôtre tourne un peu plus vite.
De toute façon, voici le code. Désolé, c'est tellement long, j'ai essayé de m'assurer que je commente, c'est bien.
La liste de vos résultats ne correspondent pas aux résultats, votre code peut produire. En particulier, vous ne montrez pas de générer l'ensemble vide.
Si j'ai été la production de powersets qui pourrait avoir quelques milliards de sous-ensembles, puis générer chaque sous-ensemble séparément plutôt que tout à la fois pourrait couper vers le bas sur votre configuration de la mémoire, l'amélioration de votre code de la vitesse. Comment à ce sujet:
Puis votre code client ressemble à ceci:
Je vais même jeter dans un peu tourner l'algorithme basé sur un modèle avec des arguments pour gratuit. Pour plus de rapidité, vous pouvez enrouler le powerlist() boucle interne dans un dangereux bloc. Il n'a pas beaucoup de différence.
Sur ma machine, ce code est légèrement plus lent que l'OP du code jusqu'à ce que les jeux sont de 16 ans ou plus. Cependant, toutes les heures à 16 éléments sont à moins de 0,15 secondes. À 23 éléments, il s'exécute dans 64% du temps. L'algorithme original ne fonctionne pas sur ma machine pour 24 ou plusieurs éléments -- il est à court de mémoire.
Ce code prend 12 secondes pour générer de la puissance pour les numéros de 1 à 24, en omettant l'écran I/O temps. C'est 16 millions-ish en 12 secondes, soit environ 1400K par seconde. Pour un milliard de dollars (qui est ce que vous avez cité plus haut), qui serait d'environ 760 secondes. Combien de temps pensez-vous que cela devrait prendre?
- T-il C ou C++ une option trop? Si C++, vous pouvez seulement de sa propre
list
type de la STL. Sinon, vous aurez à mettre en place votre propre liste - rechercher des listes chaînées ou dynamiquement la taille des tableaux de pointeurs sur la façon de le faire.Je suis d'accord avec le "optimiser .NET premier" de l'opinion. C'est la plus indolore. J'imagine que si vous avez écrit quelque gérés .NET code à l'aide de C# pointeurs, il serait identique à C d'exécution, sauf pour le traitement de l'ordinateur virtuel.
P Daddy:
Vous pouviez changer de Combinaison() code ce:
Cela permettra de réduire la multiplication et la chance de débordement à un minimum.