9
votes

Mathematica: Utilisation de simplifier pour faire une élimination et une réduction de la sous-expression courantes

Donc, Donc, j'ai joué avec la manière dont le motif de mathématica correspondant et la réécriture de terme à terme peut être mis à bien utiliser dans les optimisations du compilateur ... essayant d'optimiser fortement les blocs de code à court qui sont les parties internes des boucles. Deux manières courantes de réduire la quantité de travail nécessaire pour évaluer une expression consiste à identifier des sous-expressions qui se produisent plus d'une fois et stockent le résultat, puis utilisent le résultat stocké aux points suivants pour économiser du travail. Une autre approche consiste à utiliser des opérations moins chères dans la mesure du possible. Par exemple, ma compréhension est que prendre des racines carrées prennent plus de cycles d'horloge que des ajouts et des multiplications. Pour être claire, je suis intéressé par le coût en termes d'opérations de points flottants qui évaluant l'expression prendraient, et non combien de temps il faut Mathematica pour l'évaluer.

Ma première pensée était que je m'appropriais au problème du développement en utilisant Mathematica's Simplifier fonction. Il est possible de spécifier une fonction de complexité qui compare la simplicité relative de deux expressions. J'allais créer un en utilisant des poids pour les opérations arithmétiques appropriées et ajouter à cela la valeur de l'expression pour tenir compte des opérations d'affectation requises. Cela aborde la réduction du côté de la force, mais c'est l'élimination des sous-expressions communes qui m'a trébuché. P>

Je pensais ajouter d'une élimination commune de sousexpression aux fonctions de transformation possibles qui simplifient les utilisations. Mais pour une expression importante, il pourrait y avoir de nombreuses subexpressions possibles pouvant être remplacées et il ne sera pas possible de savoir ce qu'ils sont jusqu'à ce que vous voyiez l'expression. J'ai écrit une fonction qui donne les substitutions possibles, mais cela semble être la fonction de transformation que vous spécifiez les besoins pour renvoyer une seule transformation possible, du moins des exemples de la documentation. Toute réflexion sur la façon dont on pourrait se contenter de cette limitation? Est-ce que quelqu'un a une meilleure idée de savoir comment simplifier les fonctions de transformation qui pourrait indiquer une direction en avant? P>

J'imagine que dans les coulisses qui simplifient font une programmation dynamique en essayant différentes simplifications sur différentes parties des expressions et retourner celui avec le score de complexité le plus bas. Serais-je préférable d'essayer de faire cette programmation dynamique à mes propres simplifications algébriques communes telles que facteur et collectionner? P>

Edit: J'ai ajouté le code qui génère des sous-expressions possibles pour supprimer p> xxx pré>

Une fois qu'une sous-expression commune est choisie dans la liste renvoyée par Commonsubexpressions la fonction qui fait le remplacement est ci-dessous. P>

Input:
cost[e_] := 
 Total[MapThread[
   Count[e, #1, Infinity, Heads -> True]*#2 &, {{Plus, Times, Sqrt, 
     f}, {1, 2, 5, 10}}]]
cost[transformed]

Output:
100


3 commentaires

Salut! Voulez-vous partager votre fonction qui donne les substitutions possibles ?


Tnx! J'ai trouvé "expérimental`optimizefression" ... qui semble supprimer des calculs répétés. Toujours ne fonctionne pas pour moi, cependant.


BTW, Simplifier est plus comme une recherche heuristique qui essaie différentes règles de transformation pour rendre l'expression plus courte. Il est le pouvoir de connaître de nombreuses relations fonctionnelles spéciales, mais je rencontre souvent des expressions avec seulement exp, +, --, /, * pour laquelle Simplify ne peut pas trouver la forme la plus simple, alors que certaines règles de réécriture personnalisées a-> B font le travail


3 Réponses :


4
votes

Pour identifier les sous-expressions répétées, vous pouvez utiliser quelque chose comme celui-ci

(*helper functions to add Dictionary-like functionality*)

index[downvalue_, 
   dict_] := (downvalue[[1]] /. HoldPattern[dict[x_]] -> x) // 
   ReleaseHold;
value[downvalue_] := downvalue[[-1]];
indices[dict_] := 
  Map[#[[1]] /. {HoldPattern[dict[x_]] -> x} &, DownValues[dict]] // 
   ReleaseHold;
values[dict_] := Map[#[[-1]] &, DownValues[dict]];
items[dict_] := Map[{index[#, dict], value[#]} &, DownValues[dict]];
indexQ[dict_, index_] := 
  If[MatchQ[dict[index], HoldPattern[dict[index]]], False, True];


(*count number of times each sub-expressions occurs *)
expr = Cos[x + Cos[Cos[x] + Sin[x]]] + Cos[Cos[x] + Sin[x]];
Map[(counts[#] = If[indexQ[counts, #], counts[#] + 1, 1]; #) &, expr, 
  Infinity];
items[counts] // Column


1 commentaires

Joli! Je me demande combien de travail reste pour la construction d'un optimiseur de base.



5
votes

Il y a aussi des routines ici implémentées ici par cet auteur: http://stelone.sb.org/wordpress/2009/06/converting-symbolic-mathematica-expressions-a-c-code/

Je l'ai emballé dans un fichier * .m et j'ai corrigé un bogue (si l'expression n'a aucune subexpessions répétée, elle meurt) et j'essaie de trouver les informations de contact de l'auteur pour voir si je peux télécharger son code modifié à Pastebin ou partout où.

Edit: J'ai reçu la permission de l'auteur de le télécharger et l'avoir collé ici: http://pastebin.com/ fjyir0b3


1 commentaires

0
votes

J'ai essayé de imiter la fonction de compression du dictionnaire apparaît sur ce blog: https://writings.stephenwolfram.com/2018/11/Logic-Explainability-et-et-future-f-unStanding/

Voici ce que j'ai fait: xxx

 Entrez la description de l'image ici


0 commentaires