Que contient votre sac à outils Mathematica? [fermé]


152

Nous savons tous que Mathematica est excellent, mais il manque souvent de fonctionnalités essentielles. Quels types de packages / outils / ressources externes utilisez-vous avec Mathematica?

Je vais éditer (et inviter quiconque à le faire aussi) cet article principal pour inclure des ressources axées sur l'applicabilité générale dans la recherche scientifique et que le plus grand nombre de personnes possible trouveront utiles. N'hésitez pas à apporter quoi que ce soit, même de petits extraits de code (comme je l'ai fait ci-dessous pour une routine de chronométrage).

De plus, les fonctionnalités non documentées et utiles de Mathematica 7 et au-delà que vous avez trouvées vous-même ou que vous avez extraites d'un article / site sont les bienvenues.

Veuillez inclure une brève description ou un commentaire sur les raisons pour lesquelles quelque chose est génial ou l'utilité qu'il fournit. Si vous créez un lien vers des livres sur Amazon avec des liens d'affiliation, veuillez le mentionner, par exemple en mettant votre nom après le lien.


Paquets:

  1. LevelSchemeest un progiciel qui élargit considérablement la capacité de Mathematica à produire des graphiques de qualité. Je l'utilise sinon pour autre chose, alors pour le contrôle beaucoup plus amélioré des ticks de trame / axes. Sa dernière version s'appelle SciDraw et sortira cette année.
  2. David Park's Presentation Package(50 $ US - sans frais pour les mises à jour)
  3. Le grassmannOpspackage de Jeremy Michelson fournit des ressources pour faire de l'algèbre et du calcul avec des variables de Grassmann et des opérateurs qui ont des relations de commutation non triviales.
  4. GrassmannAlgebraPaquet et livre de John Brown pour travailler avec les algèbres de Grassmann et de Clifford.
  5. RISC (Institut de recherche pour le calcul symbolique) a une variété de packages pour Mathematica (et d'autres langues) disponibles pour téléchargement. En particulier, il y a Theorema pour la démonstration automatisée de théorèmes, et la multitude de packages pour la sommation symbolique, les équations de différence, etc. sur la page des logiciels du groupe Algorithmic Combinatorics .

Outils:

  1. MASHest l'excellent Perl de Daniel Reeves script fournissant essentiellement un support de script pour Mathematica v7. (Maintenant intégré à partir de Mathematica 8 avec l' -scriptoption.)
  2. Une alternate Mathematica shell avec une entrée readline GNU (en utilisant python, * nix uniquement)
  3. Le package ColourMaths vous permet de sélectionner visuellement des parties d'une expression et de les manipuler. http://www.dbaileyconsultancy.co.uk/colour_maths/colour_maths.html

Ressources:

  1. Le propre référentiel de Wolfram MathSourcea beaucoup de blocs-notes utiles mais étroits pour diverses applications. Consultez également les autres sections telles que

  2. Le Wikibook Mathematica .

Livres:

  1. Programmation Mathematica: une introduction avancée par Leonid Shifrin ( web, pdf) est une lecture incontournable si vous voulez faire autre chose que des boucles For dans Mathematica. Nous avons le plaisir d'avoirLeonid se voir répondre ici aux questions.
  2. Méthodes quantiques avec Mathematica par James F.Feagin ( amazon )
  3. Le livre Mathematica de Stephen Wolfram ( Amazon ) ( web)
  4. Contour de Schaum ( amazone )
  5. Mathematica in Action par Stan Wagon ( amazon ) - 600 pages d'exemples soignés et remonte à Mathematica version 7. Les techniques de visualisation sont particulièrement bonnes, vous pouvez en voir certaines sur l'auteur Demonstrations Page.
  6. Mathematica Programming Fundamentals par Richard Gaylord ( pdf) - Une bonne introduction concise à la plupart de ce que vous devez savoir sur la programmation Mathematica.
  7. Mathematica Cookbook de Sal Mangano publié par O'Reilly 2010 832 pages. - Écrit dans le style bien connu du livre de cuisine O'Reilly: Problème - Solution. Pour les intermédiaires.
  8. Equations différentielles avec Mathematica, 3e éd. Elsevier 2004 Amsterdam par Martha L. Abell, James P. Braselton - 893 pages Pour les débutants, apprenez à résoudre les DE et Mathematica en même temps.

Caractéristiques non documentées (ou à peine documentées):

  1. Comment personnaliser les raccourcis clavier de Mathematica. Voir this question.
  2. Comment inspecter les modèles et les fonctions utilisés par les propres fonctions de Mathematica. Voirthis answer
  3. Comment obtenir une taille cohérente pour les graphiques graphiques dans Mathematica? Voir this question.
  4. Comment produire des documents et des présentations avec Mathematica. Voir this question.

2
Mathematica 8 est sorti avec une bien meilleure intégration des scripts shell. wolfram.com/mathematica/new-in-8/mathematica-shell-scripts
Joshua Martell

2
+1, pour LevelScheme. C'est un peu lent, parfois. Mais, il a une méthode sensée pour créer des graduations, et il est beaucoup plus facile de créer des mises en page dignes d'un journal pour les graphiques Grid, ou quoi que ce soit de ce genre.
rcollyer

2
Comme proposé par Alexey dans les commentaires sur cette question stackoverflow.com/questions/5152551/… , j'ai proposé le changement de nom de tag pour Mathematica ici: meta.stackexchange.com/questions/81152/… . Veuillez jeter un coup d'œil et voter si vous êtes d'accord. Je la poste ici car cette question a beaucoup de favoris dans la communauté Mma ici.
Dr. belisarius

1
Dans l'ensemble, cette question devrait vraiment être un wiki de la communauté pour toutes les raisons habituelles: elle n'a pas de réponse correcte et c'est plus une liste qu'autre chose. Je m'excuse auprès de tous ceux qui ont largement profité de la réputation de cette question.
rcollyer

2
Ces réponses à cette question sont constructives, elle doit être rouverte.
MR

Réponses:


29

J'ai mentionné cela avant, mais l'outil que je trouve le plus utile est une application Reapet Sowqui imite / augment le comportement de GatherBy:

SelectEquivalents[x_List,f_:Identity, g_:Identity, h_:(#2&)]:=
   Reap[Sow[g[#],{f[#]}]&/@x, _, h][[2]];

Cela me permet de regrouper les listes selon n'importe quel critère et de les transformer dans le processus. La façon dont cela fonctionne est qu'une fonction de critères ( f) marque chaque élément de la liste, chaque élément est ensuite transformé par une deuxième fonction fournie (g ) et la sortie spécifique est contrôlée par une troisième fonction ( h). La fonction haccepte deux arguments: une balise et une liste des éléments collectés qui ont cette balise. Les articles conservent leur ordre d'origine, donc si vous définissez, h = #1&vous obtenez un non trié Union, comme dans les exemples pour Reap. Mais, il peut être utilisé pour un traitement secondaire.

À titre d'exemple de son utilité, j'ai travaillé avec Wannier90 qui génère l'hamiltonien spatialement dépendant dans un fichier où chaque ligne est un élément différent dans la matrice, comme suit

rx ry rz i j Re[Hij] Im[Hij]

Pour transformer cette liste en un ensemble de matrices, j'ai rassemblé toutes les sous-listes contenant la même coordonnée, transformé les informations d'élément en une règle (c'est-à-dire {i, j} -> Re [Hij] + I Im [Hij]), et puis a transformé les règles collectées en un SparseArraytout avec une seule ligne:

SelectEquivalents[hamlst, 
      #[[;; 3]] &, 
      #[[{4, 5}]] -> (Complex @@ #[[6 ;;]]) &, 
      {#1, SparseArray[#2]} &]

Honnêtement, c'est mon couteau suisse, et cela rend les choses complexes très simples. La plupart de mes autres outils sont quelque peu spécifiques à un domaine, donc je ne les publierai probablement pas. Cependant, la plupart d'entre eux, sinon tous, font référence SelectEquivalents.

Edit : il n'imite pas complètement GatherByen ce sens qu'il ne peut pas regrouper plusieurs niveaux de l'expression aussi simplement queGatherBy possible. Cependant, Mapfonctionne très bien pour la plupart de ce dont j'ai besoin.

Exemple : @Yaroslav Bulatov a demandé un exemple autonome. En voici une issue de mes recherches qui a été grandement simplifiée. Donc, disons que nous avons un ensemble de points dans un avion

In[1] := pts = {{-1, -1, 0}, {-1, 0, 0}, {-1, 1, 0}, {0, -1, 0}, {0, 0, 0}, 
 {0, 1, 0}, {1, -1, 0}, {1, 0, 0}, {1, 1, 0}}

et nous aimerions réduire le nombre de points par un ensemble d'opérations de symétrie. (Pour les curieux, nous générons le petit groupe de chaque point.) Pour cet exemple, utilisons un axe de rotation quadruple autour de l'axe z

In[2] := rots = RotationTransform[#, {0, 0, 1}] & /@ (Pi/2 Range[0, 3]);

En utilisant, SelectEquivalentsnous pouvons regrouper les points qui produisent le même ensemble d'images sous ces opérations, c'est-à-dire qu'ils sont équivalents, en utilisant ce qui suit

In[3] := SelectEquivalents[ pts, Union[Through[rots[#] ] ]& ] (*<-- Note Union*)
Out[3]:= {{{-1, -1, 0}, {-1, 1, 0}, {1, -1, 0}, {1, 1, 0}},
          {{-1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {1, 0, 0}},
          {{0,0,0}}}

ce qui produit 3 sous-listes contenant les points équivalents. (Remarque,Union c'est absolument vital ici car cela garantit que la même image est produite par chaque point. À l'origine, j'ai utilisé Sort, mais si un point se trouve sur un axe de symétrie, il est invariant sous la rotation autour de cet axe donnant une image supplémentaire de lui-même . Donc, Unionélimine ces images supplémentaires. Aussi, GatherByproduirait le même résultat.) Dans ce cas, les points sont déjà sous une forme que j'utiliserai, mais je n'ai besoin que d'un point représentatif de chaque groupement et j'aimerais un décompte des points équivalents. Depuis, je n'ai pas besoin de transformer chaque point, j'utilise leIdentityfonction en deuxième position. Pour la troisième fonction, nous devons être prudents. Le premier argument qui lui sera passé sera les images des points sous les rotations qui pour le point {0,0,0}sont une liste de quatre éléments identiques, et l'utiliser annulerait le décompte. Cependant, le deuxième argument est juste une liste de tous les éléments qui ont cette balise, donc il ne contiendra que {0,0,0}. Dans du code,

In[4] := SelectEquivalents[pts,  
             Union[Through[rots[#]]]&, #&, {#2[[1]], Length[#2]}& ]
Out[4]:= {{{-1, -1, 0}, 4}, {{-1, 0, 0}, 4}, {{0, 0, 0}, 1}}

Notez que cette dernière étape peut tout aussi facilement être accomplie en

In[5] := {#[[1]], Length[#]}& /@ Out[3]

Mais, il est facile avec cet exemple et l'exemple moins complet ci-dessus de voir comment des transformations très complexes sont possibles avec un minimum de code.


Le code original Fortran77 a été restructuré le jour de Thanksgiving 1996, et donc pendant de nombreuses années connu sous le nom de turkey.f ...: D Très beaux graphismes BTW. M'a rappelé le monstre de Falicov ...
Dr belisarius

@belisarius, je n'avais pas lu l'histoire, c'est drôle. Je viens de commencer à utiliser Wannier90, mais c'est l'un des Fortrancodes les mieux organisés et les mieux écrits que j'ai vu. Cela me fait presque envisager d'utiliser Fortran...
rcollyer

Je me demande si vous pourriez ajouter un exemple autonome de SelectEquivalents en action
Yaroslav Bulatov

@Yaroslav Bulatov, a ajouté un exemple, par demande. Faites-moi savoir si cela vous aide. Sinon, nous verrons ce que nous pouvons faire.
rcollyer

Vous obtenez la coche à cette "question" pour la contribution d'extrait de code la plus intéressante.
Timo

57

L'un des avantages de l'interface du notebook Mathematica est qu'elle peut évaluer des expressions dans n'importe quel langage, pas seulement Mathematica. À titre d'exemple simple, envisagez de créer un nouveau type de cellule d'entrée Shell qui transmet l'expression contenue au shell du système d'exploitation pour évaluation.

Tout d'abord, définissez une fonction qui délègue l'évaluation d'une commande textuelle au shell externe:

shellEvaluate[cmd_, _] := Import["!"~~cmd, "Text"]

Le deuxième argument est nécessaire et ignoré pour des raisons qui apparaîtront plus tard. Ensuite, nous voulons créer un nouveau style appelé Shell :

  1. Ouvrez un nouveau bloc-notes.
  2. Sélectionnez l'élément de menu Format / Modifier la feuille de style ...
  3. Dans la boîte de dialogue, à côté de Entrez un nom de style: tapez Shell.
  4. Sélectionnez le crochet de cellule à côté du nouveau style.
  5. Sélectionnez l'élément de menu Cellule / Afficher l'expression
  6. Remplacez l'expression de la cellule par le texte de l' étape 6 ci-dessous.
  7. Une fois de plus, sélectionnez l'élément de menu Cellule / Afficher l'expression
  8. Fermez la boîte de dialogue.

Utilisez l'expression de cellule suivante comme texte de l' étape 6 :

Cell[StyleData["Shell"],
 CellFrame->{{0, 0}, {0.5, 0.5}},
 CellMargins->{{66, 4}, {0, 8}},
 Evaluatable->True,
 StripStyleOnPaste->True,
 CellEvaluationFunction->shellEvaluate,
 CellFrameLabels->{{None, "Shell"}, {None, None}},
 Hyphenation->False,
 AutoQuoteCharacters->{},
 PasteAutoQuoteCharacters->{},
 LanguageCategory->"Formula",
 ScriptLevel->1,
 MenuSortingValue->1800,
 FontFamily->"Courier"]

La plupart de cette expression a été copiée directement à partir du style Program intégré . Les principaux changements sont ces lignes:

 Evaluatable->True,
 CellEvaluationFunction->shellEvaluate,
 CellFrameLabels->{{None, "Shell"}, {None, None}},

Evaluatableactive la fonctionnalité SHIFT + ENTER pour la cellule. L'évaluation appellera le CellEvaluationFunctionpassage du contenu de la cellule et du type de contenu comme arguments ( shellEvaluateignore ce dernier argument). CellFrameLabelsest juste une subtilité qui permet à l'utilisateur d'identifier que cette cellule est inhabituelle.

Avec tout cela en place, nous pouvons maintenant entrer et évaluer une expression shell:

  1. Dans le bloc-notes créé dans les étapes ci-dessus, créez une cellule vide et sélectionnez le crochet de cellule.
  2. Sélectionnez l'élément de menu Format / Style / Shell .
  3. Tapez une commande shell du système d'exploitation valide dans la cellule (par exemple «ls» sous Unix ou «dir» sous Windows).
  4. Appuyez sur MAJ + ENTRÉE.

Il est préférable de conserver ce style défini dans une feuille de style située au centre. De plus, les fonctions d'évaluation telles que shellEvaluatesont mieux définies comme des stubs à l' aide de DeclarePackage dansinit.m . Les détails de ces deux activités dépassent le cadre de cette réponse.

Avec cette fonctionnalité, on peut créer des cahiers qui contiennent des expressions d'entrée dans n'importe quelle syntaxe d'intérêt. La fonction d'évaluation peut être écrite en pure Mathematica, ou déléguer tout ou partie de l'évaluation à une agence externe. Sachez qu'il existe d'autres crochets qui se rapportent à l' évaluation cellulaire, comme CellEpilog, CellProloget CellDynamicExpression.

Un modèle courant consiste à écrire le texte de l'expression d'entrée dans un fichier temporaire, à compiler le fichier dans une langue, à exécuter le programme et à capturer la sortie pour un affichage final dans la cellule de sortie. Il y a beaucoup de détails à aborder lors de la mise en œuvre d'une solution complète de ce type (comme la capture correcte des messages d'erreur), mais il faut apprécier le fait qu'il est non seulement possible de faire des choses comme celle-ci, mais aussi pratique.

Sur une note personnelle, ce sont des fonctionnalités comme celle-ci qui font de l'interface du notebook le centre de mon univers de programmation.

Mettre à jour

La fonction d'assistance suivante est utile pour créer de telles cellules:

evaluatableCell[label_String, evaluationFunction_] :=
  ( CellPrint[
      TextCell[
        ""
      , "Program"
      , Evaluatable -> True
      , CellEvaluationFunction -> (evaluationFunction[#]&)
      , CellFrameLabels -> {{None, label}, {None, None}}
      , CellGroupingRules -> "InputGrouping"
      ]
    ]
  ; SelectionMove[EvaluationNotebook[], All, EvaluationCell]
  ; NotebookDelete[]
  ; SelectionMove[EvaluationNotebook[], Next, CellContents]
  )

Il est utilisé ainsi:

shellCell[] := evaluatableCell["shell", Import["!"~~#, "Text"] &]

Désormais, si shellCell[]est évalué, la cellule d'entrée sera supprimée et remplacée par une nouvelle cellule d'entrée qui évalue son contenu comme une commande shell.


3
@WReach +100! J'aurais aimé le savoir plus tôt! C'est un truc très utile, du moins pour moi. Merci d'avoir partagé!
Leonid Shifrin

Cela a l'air assez spiffy! CellEvaluationFunctionpourrait être utilisé pour le piratage de syntaxe de bas niveau aussi je pense.
Mr.Wizard

@Leonid Au moins pour le FrontEnd, est CellEvaluationFunctionle crochet que vous recherchiez?
Mr.Wizard

2
De plus: il existe une autre Celloption liée à l'évaluation des cellules - Evaluator -> "EvaluatorName". La signification de "EvaluatorName"peut être configurée via la boîte de dialogue Evaluation :: Kernel Configuration Options .... Je ne sais toujours pas s'il est possible de le configurer par programmation ... Cette technique permet d'utiliser différents MathKernels dans différents Cells dans un seul Notebook. Ces MathKernels peuvent provenir de différentes versions de Mathematica installées.
Alexey Popkov

1
@Szabolcs Toutes mes propres utilisations de cette technique impliquent soit une approche stdin _ / _ stdout comme illustré ci-dessus, soit une requête distante autonome telle qu'une requête SQL ou une opération HTTP. Vous pouvez essayer de configurer une application Web Python REPL (comme celle-ci ) et d'interagir avec elle en utilisant Import, ou peut-être en démarrant un processus Python externe et en communiquant via ses flux (par exemple en utilisant un Java ProcessBuilder ). Je suis sûr qu'il y a une meilleure façon de Mathematica - cela ressemble à une bonne question SO :)
WReach

36

Todd Gayley (Wolfram Research) vient de m'envoyer un joli hack qui permet de "envelopper" les fonctions intégrées avec du code arbitraire. Je sens que je dois partager cet instrument utile. Ce qui suit est la réponse de Todd sur mon question.

Un peu d'histoire intéressante (?): Ce style de hack pour "envelopper" une fonction intégrée a été inventé vers 1994 par Robby Villegas et moi, ironiquement pour la fonction Message, dans un package appelé ErrorHelp que j'ai écrit pour le Mathematica Journal à l'époque. Il a été utilisé de nombreuses fois, par de nombreuses personnes, depuis lors. C'est un peu une astuce d'initié, mais je pense qu'il est juste de dire que c'est devenu la manière canonique d'injecter votre propre code dans la définition d'une fonction intégrée. Cela fait bien le travail. Vous pouvez, bien sûr, placer la variable $ inMsg dans n'importe quel contexte privé que vous souhaitez.

Unprotect[Message];

Message[args___] := Block[{$inMsg = True, result},
   "some code here";
   result = Message[args];
   "some code here";
   result] /; ! TrueQ[$inMsg]

Protect[Message];

@Alexey J'ai du mal à comprendre cela. Pouvez-vous expliquer comment cela fonctionne? Ne devrait-il pas y avoir un [Message] Unprotect quelque part? Et cet exemple ne contient-il pas une récursion infinie? Et, ! TrueQ [$ inMsg] est-ce que cela a du sens avec $ inMsg défini dans la portée Block et indéfini en dehors de Block?
Sjoerd C. de Vries

9
@Sjoerd D'après ce que je comprends, le Unprotectdoit en effet être, a été simplement laissé de côté. Le but de Block(portée dynamique) et $inMsgest exactement d'empêcher une récursion infinie. Parce que $inMsgn'est pas défini à l'extérieur (c'est une exigence importante), dans un premier temps, TrueQévalue à False, et nous entrons dans le corps de la fonction. Mais lorsque nous avons l'appel de fonction à l'intérieur du corps, la condition est évaluée à False(puisque la variable a été redéfinie par Block). Ainsi, la règle définie par l'utilisateur ne correspond pas et la règle intégrée est utilisée à la place.
Leonid Shifrin

1
@Leonid Merci, je comprends maintenant. Très intelligent!
Sjoerd C. de Vries

1
Je viens de découvrir que cette technique a été discutée par Robby Villegas de Wolfram Research lors de la conférence des développeurs de 1999. Voir le cahier «Travailler avec des expressions non évaluées» publié ici . Dans ce cahier, Robby Villegas discute de cette astuce dans la sous-section "My Block astuce pour intercepter les appels aux fonctions intégrées".
Alexey Popkov

1
@ Mr.Wizard Ce n'est pas la seule façon de faire cela. Pendant longtemps, j'ai utilisé une version où vous redéfinissez le DownValuesau moment de l'exécution, vous pouvez consulter ce post groups.google.com/group/comp.soft-sys.math.mathematica/… , pour un exemple ( SetDelayedredéfinition) . Mais ma méthode est moins élégante, moins robuste, plus sujette aux erreurs et rend la rupture de la récursivité beaucoup moins simple à mettre en œuvre. Ainsi, dans la plupart des situations, la méthode décrite par @Alexey l'emporte haut la main.
Leonid Shifrin

25

Ce n'est pas une ressource complète, donc je la jette ici dans la section des réponses, mais je l'ai trouvée très utile pour déterminer les problèmes de vitesse (ce qui, malheureusement, est une grande partie de la programmation Mathematica).

timeAvg[func_] := Module[
{x = 0, y = 0, timeLimit = 0.1, p, q, iterTimes = Power[10, Range[0, 10]]},
Catch[
 If[(x = First[Timing[(y++; Do[func, {#}]);]]) > timeLimit,
    Throw[{x, y}]
    ] & /@ iterTimes
 ] /. {p_, q_} :> p/iterTimes[[q]]
];
Attributes[timeAvg] = {HoldAll};

L'utilisation est alors simple timeAvg@funcYouWantToTest.

EDIT: M. Wizard a fourni une version plus simple qui supprime Throwet Catchet est un peu plus facile à analyser:

SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] := Do[If[# > 0.3, Return[#/5^i]] & @@ 
                     Timing @ Do[func, {5^i}]
                     ,{i, 0, 15}]

EDIT: Voici une version de acl (tirée d' ici ):

timeIt::usage = "timeIt[expr] gives the time taken to execute expr, \
  repeating as many times as necessary to achieve a total time of 1s";

SetAttributes[timeIt, HoldAll]
timeIt[expr_] := Module[{t = Timing[expr;][[1]], tries = 1},
  While[t < 1., tries *= 2; t = Timing[Do[expr, {tries}];][[1]];]; 
  t/tries]

Je l'ai fait encore et encore ... il est temps d'entrer dans mon propre sac. tnx!
Dr. belisarius

1
Un problème avec ce code (enfin, peut-être que c'est le point de vue d'un perfectionniste) est que nous pouvons attraper quelque chose que nous n'avons pas lancé et interpréter cela comme un résultat de synchronisation incorrect. Les deux Catchet Throwauraient dû être utilisés avec des balises d'exception uniques.
Leonid Shifrin

2
Timo, je suis heureux que vous aimiez mon interprétation suffisamment pour l'inclure. Merci de m'avoir rendu hommage aussi. Je suis curieux de savoir comment vous avez reformaté mon code. Je ne suis pas de directives particulières dans mon propre code, à part le rendre facile à lire moi-même; Y a-t-il une école de pensée derrière votre reformatage, ou est-ce juste une préférence? Mathematica n'encourage pas le formatage précis du code en raison de la façon dont il reflète l'entrée, mais poster du code ici me fait commencer à y réfléchir. BTW, je pense que vous voulez dire " Throwet Catch" plutôt que " Reapet Sow".
Mr.Wizard

1
@Simon, Mr.Wizard, j'utilise cette méthode pour chronométrer différentes versions de petites fonctions qui seront appelées beaucoup de fois. Pas nécessairement dans une structure en boucle mais certainement dans des constructions optimisées par MMA. Dans ce contexte, la synchronisation de l'exécution d'une boucle a du sens et les performances seront proches de l'application réelle. Pour chronométrer de grandes fonctions complexes (peut-être même des cellules d'initialisation entières), la méthode de Simon donnera un meilleur résultat. Dans l'ensemble, je suis plus intéressé par les valeurs relatives et les deux méthodes devraient y fonctionner.
Timo

3
Il y a maintenant RepeatedTimingà faire.
masterxilo

20

Internal`InheritedBlock

J'ai appris récemment l'existence d'une fonction aussi utile que Internal`InheritedBlock, de ce message de Daniel Lichtblau dans le newsgroup officiel.

Si je comprends bien, Internal`InheritedBlockpermet de transmettre une copie d'une fonction sortante à l'intérieur de la Blockportée:

In[1]:= Internal`InheritedBlock[{Message},
Print[Attributes[Message]];
Unprotect[Message];
Message[x___]:=Print[{{x},Stack[]}];
Sin[1,1]
]
Sin[1,1]
During evaluation of In[1]:= {HoldFirst,Protected}
During evaluation of In[1]:= {{Sin::argx,Sin,2},{Internal`InheritedBlock,CompoundExpression,Sin,Print,List}}
Out[1]= Sin[1,1]
During evaluation of In[1]:= Sin::argx: Sin called with 2 arguments; 1 argument is expected. >>
Out[2]= Sin[1,1]

Je pense que cette fonction peut être très utile pour tous ceux qui ont besoin de modifier temporairement les fonctions intégrées!

Comparaison avec Block

Définissons une fonction:

a := Print[b]

Nous souhaitons maintenant passer une copie de cette fonction dans la Blockportée. Le procès naïf ne donne pas ce que l'on veut:

In[2]:= Block[{a = a}, OwnValues[a]]

During evaluation of In[9]:= b

Out[2]= {HoldPattern[a] :> Null}

Maintenant, essayez d'utiliser la définition retardée dans le premier argument de Block(c'est aussi une fonctionnalité non documentée):

In[3]:= Block[{a := a}, OwnValues[a]]
Block[{a := a}, a]

Out[3]= {HoldPattern[a] :> a}

During evaluation of In[3]:= b

Nous voyons que dans ce cas afonctionne mais nous n'avons pas de copie de l'original à l' aintérieur duBlock portée.

Essayons maintenant Internal`InheritedBlock:

In[5]:= Internal`InheritedBlock[{a}, OwnValues[a]]

Out[5]= {HoldPattern[a] :> Print[b]}

Nous avons une copie de la définition originale pour l' aintérieur de la Blockportée et nous pouvons la modifier comme nous le souhaitons sans affecter la définition globale de a!


+1 Très pratique! Un outil de plus dans le sac, et 10 points plus près du privilège Modifier pour vous.
Mr.Wizard

Pour moi, cela apparaît comme une variante de l'évaluation précoce ou tardive ou non et complète.
user2432923

19

Mathematica est un outil pointu, mais il peut vous couper avec son comportement quelque peu non typé et ses avalanches de messages de diagnostic cryptiques . Une façon de gérer cela est de définir des fonctions en suivant cet idiome:

ClearAll@zot
SetAttributes[zot, ...]
zot[a_] := ...
zot[b_ /; ...] := ...
zot[___] := (Message[zot::invalidArguments]; Abort[])

C'est beaucoup de passe-partout, que je suis souvent tenté de sauter. Surtout lors du prototypage, ce qui arrive souvent dans Mathematica. Du coup, j'utilise une macro appelée definequi me permet de rester disciplinée, avec beaucoup moins de passe-partout.

Une utilisation basique de defineest comme ceci:

define[
  fact[0] = 1
; fact[n_ /; n > 0] := n * fact[n-1]
]

fact[5]

120

Cela ne semble pas grand-chose au début, mais il y a des avantages cachés. Le premier service qui definefournit est qu'il s'applique automatiquementClearAll au symbole en cours de définition. Cela garantit qu'il n'y a pas de définitions restantes - une occurrence courante lors du développement initial d'une fonction.

Le deuxième service est que la fonction en cours de définition est automatiquement "fermée". Je veux dire par là que la fonction émettra un message et abandonnera si elle est invoquée avec une liste d'arguments qui ne correspond pas à l'une des définitions:

fact[-1]

define::badargs: There is no definition for 'fact' applicable to fact[-1].
$Aborted

Il s'agit de la valeur principale de define, qui détecte une classe d'erreur très courante.

Une autre commodité est une manière concise de spécifier les attributs de la fonction en cours de définition. Faisons la fonction Listable:

define[
  fact[0] = 1
; fact[n_ /; n > 0] := n * fact[n-1]
, Listable
]

fact[{3, 5, 8}]

{6, 120, 40320}

En plus de tous les attributs normaux, defineaccepte un attribut supplémentaire appelé Open. Cela empêche defined'ajouter la définition d'erreur fourre-tout à la fonction:

define[
  successor[x_ /; x > 0] := x + 1
, Open
]

successor /@ {1, "hi"}

{2, successor["hi"]}

Plusieurs attributs peuvent être définis pour une fonction:

define[
  flatHold[x___] := Hold[x]
, {Flat, HoldAll}
]

flatHold[flatHold[1+1, flatHold[2+3]], 4+5]

Hold[1 + 1, 2 + 3, 4 + 5]

Sans plus tarder, voici la définition de define:

ClearAll@define
SetAttributes[define, HoldAll]
define[body_, attribute_Symbol] := define[body, {attribute}]
define[body:(_Set|_SetDelayed), attributes_List:{}] := define[CompoundExpression[body], attributes]
define[body:CompoundExpression[((Set|SetDelayed)[name_Symbol[___], _])..], attributes_List:{}] :=
  ( ClearAll@name
  ; SetAttributes[name, DeleteCases[attributes, Open]]
  ; If[!MemberQ[attributes, Open]
    , def:name[___] := (Message[define::badargs, name, Defer@def]; Abort[])
    ]
  ; body
  ;
  )
def:define[___] := (Message[define::malformed, Defer@def]; Abort[])

define::badargs = "There is no definition for '``' applicable to ``.";
define::malformed = "Malformed definition: ``";

L'implémentation présentée ne prend en charge ni les valeurs haussières, ni le currying, ni les modèles plus généraux qu'une simple définition de fonction. Cela reste cependant utile.


2
+1 - ce sont des trucs vraiment utiles. J'utilise des outils similaires. Les macros (ainsi que l'introspection et d'autres techniques de méta-programmation) peuvent être très puissantes, mais semblent généralement sous-estimées au sein de la communauté Mathematica, ou du moins cela a été mon impression jusqu'à présent.
Leonid Shifrin

Je viens de définir quelque chose de similaire. +1 pour le support CompoundExpression pour faire plusieurs définitions, Abort [] (semble mieux que encore plus de messages) et Open (bien pour les constructeurs par exemple).
masterxilo

16

Commencez sans ouvrir un cahier vierge

Cela me dérangeait de faire démarrer Mathematica avec un cahier vierge ouvert. Je pourrais fermer ce cahier avec un script, mais il s'ouvrirait encore brièvement. Mon hack est de créer un fichier Invisible.nbcontenant:

Notebook[{},Visible->False]

Et ajoutez ceci à mon Kernel\init.m:

If[Length[Notebooks["Invisible*"]] > 0, 
  NotebookClose[Notebooks["Invisible*"][[1]]]
]

SetOptions[$FrontEnd,
  Options[$FrontEnd, NotebooksMenu] /. 
    HoldPattern["Invisible.nb" -> {__}] :> Sequence[]
]

Je lance maintenant Mathematica en ouvrant Invisible.nb

Il y a peut-être un meilleur moyen, mais cela m'a bien servi.


Personnalisé FoldetFoldList

Fold[f, x] est rendu équivalent à Fold[f, First@x, Rest@x]

Soit dit en passant, je pense que cela pourrait se retrouver dans une future version de Mathematica.

Surprise! Cela a été mis en œuvre, bien qu'il ne soit actuellement pas documenté. On m'informe qu'il a été mis en œuvre en 2011 par Oliver Ruebenkoenig, apparemment peu de temps après avoir publié ceci. Merci Oliver Ruebenkoenig!

Unprotect[Fold, FoldList]

Fold[f_, h_[a_, b__]] := Fold[f, Unevaluated @ a, h @ b]
FoldList[f_, h_[a_, b__]] := FoldList[f, Unevaluated @ a, h @ b]

(* Faysal's recommendation to modify SyntaxInformation *)
SyntaxInformation[Fold]     = {"ArgumentsPattern" -> {_, _, _.}};
SyntaxInformation[FoldList] = {"ArgumentsPattern" -> {_, _., {__}}};

Protect[Fold, FoldList]

Mis à jour pour permettre ceci:

SetAttributes[f, HoldAll]
Fold[f, Hold[1 + 1, 2/2, 3^3]]
f[f[1 + 1, 2/2], 3^3]

"Partition dynamique"

Voir Mathematica.SE post # 7512 pour une nouvelle version de cette fonction.

Souvent, je souhaite partitionner une liste selon une séquence de longueurs.

exemple de pseudo-code:

partition[{1,2,3,4,5,6}, {2,3,1}]

Production: {{1,2}, {3,4,5}, {6}}

Je suis venu avec ceci:

dynP[l_, p_] := 
 MapThread[l[[# ;; #2]] &, {{0} ~Join~ Most@# + 1, #} &@Accumulate@p]

Ce que j'ai ensuite complété avec ceci, y compris les tests d'argument:

dynamicPartition[l_List, p : {_Integer?NonNegative ..}] :=
  dynP[l, p] /; Length@l >= Tr@p

dynamicPartition[l_List, p : {_Integer?NonNegative ..}, All] :=
  dynP[l, p] ~Append~ Drop[l, Tr@p] /; Length@l >= Tr@p

dynamicPartition[l_List, p : {_Integer?NonNegative ..}, n__ | {n__}] :=
  dynP[l, p] ~Join~ Partition[l ~Drop~ Tr@p, n] /; Length@l >= Tr@p

Le troisième argument contrôle ce qui arrive aux éléments au-delà de la spécification fractionnée.


Astuces Mathematica de Szabolcs

Celui que j'utilise le plus fréquemment est la palette de données tabulaires Coller

CreatePalette@
 Column@{Button["TSV", 
    Module[{data, strip}, 
     data = NotebookGet[ClipboardNotebook[]][[1, 1, 1]];
     strip[s_String] := 
      StringReplace[s, RegularExpression["^\\s*(.*?)\\s*$"] -> "$1"];
     strip[e_] := e;
     If[Head[data] === String, 
      NotebookWrite[InputNotebook[], 
       ToBoxes@Map[strip, ImportString[data, "TSV"], {2}]]]]], 
   Button["CSV", 
    Module[{data, strip}, 
     data = NotebookGet[ClipboardNotebook[]][[1, 1, 1]];
     strip[s_String] := 
      StringReplace[s, RegularExpression["^\\s*(.*?)\\s*$"] -> "$1"];
     strip[e_] := e;
     If[Head[data] === String, 
      NotebookWrite[InputNotebook[], 
       ToBoxes@Map[strip, ImportString[data, "CSV"], {2}]]]]], 
   Button["Table", 
    Module[{data}, data = NotebookGet[ClipboardNotebook[]][[1, 1, 1]];
     If[Head[data] === String, 
      NotebookWrite[InputNotebook[], 
       ToBoxes@ImportString[data, "Table"]]]]]}

Modifier les données externes de l'intérieur Compile

Récemment, Daniel Lichtblau a montré cette méthode que je n'avais jamais vue auparavant. À mon avis, cela étend considérablement l'utilité deCompile

ll = {2., 3., 4.};
c = Compile[{{x}, {y}}, ll[[1]] = x; y];

c[4.5, 5.6]

ll

(* Out[1] = 5.6  *)

(* Out[2] = {4.5, 3., 4.}  *)

3
+1 Une bonne collection! En ce qui concerne les modifications externes de l'intérieur Compile- tout mon message ici: stackoverflow.com/questions/5246330/… , était de présenter cette possibilité dans un cadre non trivial (il y avait déjà une solution plus courte et plus rapide au problème en question) . IMO, la plus grande victoire ici est la possibilité d'émuler le passage par référence et de diviser les grandes fonctions compilées en morceaux plus faciles à gérer et réutilisables.
Leonid Shifrin

1
Vous pouvez également régler les informations de syntaxe de Fold et FoldList dans votre nouvelle définition: SyntaxInformation [Pliage] = { "ArgumentsPattern" -> {_, . , _}}; SyntaxInformation [FoldList] = {"ArgumentsPattern" -> {_, _., {_ }}};
faysou

14

Problèmes et solutions d'exportation PDF / EMF généraux

1) C'est complètement inattendu et non documenté, mais Mathematica exporte et enregistre les graphiques aux formats PDF et EPS à l'aide d'un ensemble de définitions de style différent de celui utilisé pour afficher les blocs-notes à l'écran. Par défaut, les blocs-notes sont affichés à l'écran dans l'environnement de style "Travail" (qui est la valeur par défaut pour l' option ScreenStyleEvironmentglobale $FrontEnd) mais sont imprimés dans l' "Printout"environnement de style (qui est la valeur par défaut pour l' option PrintingStyleEnvironmentglobale $FrontEnd). Quand on exporte des graphiques dans des formats raster tels que GIF et PNG ou au format EMF, Mathematica génère des graphiques qui ressemblent exactement à ce qu'ils ressemblent à l'intérieur de Notebook. Il semble que le"Working"l'environnement de style est utilisé pour le rendu dans ce cas. Mais ce n'est pas le cas lorsque vous exportez / enregistrez quoi que ce soit au format PDF ou EPS! Dans ce cas, l' "Printout"environnement de style est utilisé par défautqui diffère très profondément de l'environnement de style "Travail". Tout d'abord, l' "Printout"environnement de style est fixé Magnificationà 80% . Deuxièmement, il utilise ses propres valeurs pour les tailles de police de styles différents, ce qui entraîne des changements de taille de police incohérents dans le fichier PDF généré par rapport à la représentation originale à l'écran. Ces dernières peuvent être appelées des fluctuations de FontSize qui sont très ennuyeuses. Mais heureusement, cela peut être évité en définissant l' option PrintingStyleEnvironmentglobale $FrontEndsur "Working" :

SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"]

2) Le problème commun avec l'exportation au format EMF est que la plupart des programmes (pas seulement Mathematica ) génèrent un fichier qui a l'air bien à la taille par défaut mais qui devient moche lorsque vous le zoomez. C'est parce que les métafichiers sont échantillonnés avec la fidélité de résolution d'écran . La qualité du fichier EMF généré peut être améliorée en Magnifyutilisant l'objet graphique d'origine de sorte que l'exactitude de l'échantillonnage des graphiques d'origine devienne beaucoup plus précise. Comparez deux fichiers:

graphics1 = 
  First@ImportString[
    ExportString[Style["a", FontFamily -> "Times"], "PDF"], "PDF"];
graphics2 = Magnify[graphics1, 10];
Export["C:\\test1.emf", graphics1]
Export["C:\\test2.emf", graphics2]

Si vous insérez ces fichiers dans Microsoft Word et les zoomez, vous verrez que le premier "a" a une dent de scie dessus alors que le second n'en a pas (testé avec Mathematica 6).

Une autre solution a ImageResolutionété suggérée par Chris Degnen (cette option a au moins effet à partir de Mathematica 8):

Export["C:\\test1.emf", graphics1]
Export["C:\\test2.emf", graphics1, ImageResolution -> 300]

3) Dans Mathematica, nous avons trois façons de convertir des graphiques en métafichier: via Exportto "EMF"(méthode fortement recommandée: produit un métafichier avec la plus haute qualité possible), via l' Save selection As...élément de menu ( produit un chiffre beaucoup moins précis , non recommandé) et via l' Edit ► Copy As ► Metafileélément de menu ( je recommande fortement contre cette route ).


13

À la demande générale, le code pour générer le tracé des 10 premiers répondeurs SO (à l'exception des annotations ) à l'aide de l' API SO .

entrez la description de l'image ici

getRepChanges[userID_Integer] :=
 Module[{totalChanges},
  totalChanges = 
   "total" /. 
    Import["http://api.stackoverflow.com/1.1/users/" <> 
      ToString[userID] <> "/reputation?fromdate=0&pagesize=10&page=1",
      "JSON"];
  Join @@ Table[
    "rep_changes" /. 
     Import["http://api.stackoverflow.com/1.1/users/" <> 
       ToString[userID] <> 
       "/reputation?fromdate=0&pagesize=10&page=" <> ToString[page], 
      "JSON"],
    {page, 1, Ceiling[totalChanges/10]}
    ]
  ]

topAnswerers = ({"display_name", 
      "user_id"} /. #) & /@ ("user" /. ("top_users" /. 
      Import["http://api.stackoverflow.com/1.1/tags/mathematica/top-\
answerers/all-time", "JSON"]))

repChangesTopUsers =
  Monitor[Table[
    repChange = 
     ReleaseHold[(Hold[{DateList[
              "on_date" + AbsoluteTime["January 1, 1970"]], 
             "positive_rep" - "negative_rep"}] /. #) & /@ 
        getRepChanges[userID]] // Sort;
    accRepChange = {repChange[[All, 1]], 
       Accumulate[repChange[[All, 2]]]}\[Transpose],
    {userID, topAnswerers[[All, 2]]}
    ], userID];

pl = DateListLogPlot[
  Tooltip @@@ 
   Take[({repChangesTopUsers, topAnswerers[[All, 1]]}\[Transpose]), 
    10], Joined -> True, Mesh -> None, ImageSize -> 1000, 
  PlotRange -> {All, {10, All}}, 
  BaseStyle -> {FontFamily -> "Arial-Bold", FontSize -> 16}, 
  DateTicksFormat -> {"MonthNameShort", " ", "Year"}, 
  GridLines -> {True, None}, 
  FrameLabel -> (Style[#, FontSize -> 18] & /@ {"Date", "Reputation", 
      "Top-10 answerers", ""})]

1
Brett a posté une question demandant presque ce code exact. C'est peut-être le plus approprié là-bas, avec un ou deux ajustements pour répondre à la question. Je vais en fait valoir la peine d'être répété, par opposition à sur cette question.
rcollyer le

@rcollyer a raison. Ceci est "Community Wiki"
Dr. belisarius

@belisarius Je viens de le copier dans la réponse à la question de Brett ...
Sjoerd C. de Vries

@Sjoerd Your Plot ici ne se met pas à jour automatiquement.
Dr. belisarius

@belisarius En fait, j'espérais que vous alliez prendre cette tâche sur vous ... ;-)
Sjoerd C. de Vries

13

Mettre en cache des expressions

Je trouve ces fonctions très utiles pour mettre en cache toute expression. La chose intéressante ici pour ces deux fonctions est que l'expression maintenue elle-même est utilisée comme clé de la table de hachage / symbole Cache ou CacheIndex, par rapport à la mémorisation bien connue de Mathematica où vous ne pouvez mettre en cache le résultat que si la fonction est définie comme f [x_]: = f [x] = ... Ainsi, vous pouvez mettre en cache n'importe quelle partie d'un code, c'est utile si une fonction doit être appelée plusieurs fois mais que certaines parties du code ne doivent pas être recalculées.

Pour mettre en cache une expression indépendamment de ses arguments.

SetAttributes[Cache, HoldFirst];
c:Cache[expr_] := c = expr;

Ex: Cache[Pause[5]; 6]
Cache[Pause[5]; 6]

La deuxième fois, l'expression renvoie 6 sans attendre.

Pour mettre en cache une expression à l'aide d'une expression d'alias qui peut dépendre d'un argument de l'expression mise en cache.

SetAttributes[CacheIndex, HoldRest];
c:CacheIndex[index_,expr_] := c = expr;

Ex: CacheIndex[{"f",2},x=2;y=4;x+y]

Si expr prend un certain temps à calculer, il est beaucoup plus rapide d'évaluer {"f", 2} par exemple pour récupérer le résultat mis en cache.

Pour une variation de ces fonctions afin d'avoir un cache localisé (c'est-à-dire que la mémoire cache est automatiquement libérée en dehors de la construction Block), voir ce post Eviter les appels répétés à l'interpolation

Suppression des valeurs mises en cache

Pour supprimer les valeurs mises en cache lorsque vous ne connaissez pas le nombre de définitions d'une fonction. Je considère que les définitions ont un blanc quelque part dans leurs arguments.

DeleteCachedValues[f_] := 
       DownValues[f] = Select[DownValues[f], !FreeQ[Hold@#,Pattern]&];

Pour supprimer les valeurs mises en cache lorsque vous connaissez le nombre de définitions d'une fonction (va légèrement plus vite).

DeleteCachedValues[f_,nrules_] := 
       DownValues[f] = Extract[DownValues[f], List /@ Range[-nrules, -1]];

Cela utilise le fait que les définitions d'une fonction sont à la fin de leur liste DownValues, les valeurs mises en cache avant.

Utilisation de symboles pour stocker des données et des fonctions de type objet

Voici également des fonctions intéressantes pour utiliser des symboles comme des objets.

Il est déjà bien connu que vous pouvez stocker des données dans des symboles et y accéder rapidement en utilisant DownValues

mysymbol["property"]=2;

Vous pouvez accéder à la liste des clés (ou propriétés) d'un symbole en utilisant ces fonctions en fonction de ce que les dreeves ont soumis dans un message sur ce site:

SetAttributes[RemoveHead, {HoldAll}];
RemoveHead[h_[args___]] := {args};
NKeys[symbol_] := RemoveHead @@@ DownValues[symbol(*,Sort->False*)][[All,1]];
Keys[symbol_] := NKeys[symbol] /. {x_} :> x;

J'utilise beaucoup cette fonction pour afficher toutes les infos contenues dans les DownValues ​​d'un symbole:

PrintSymbol[symbol_] :=
  Module[{symbolKeys},
    symbolKeys = Keys[symbol];
    TableForm@Transpose[{symbolKeys, symbol /@ symbolKeys}]
  ];

Enfin, voici un moyen simple de créer un symbole qui se comporte comme un objet en programmation orientée objet (il reproduit simplement le comportement le plus basique de la POO mais je trouve la syntaxe élégante):

Options[NewObject]={y->2};
NewObject[OptionsPattern[]]:=
  Module[{newObject},
    newObject["y"]=OptionValue[y];

    function[newObject,x_] ^:= newObject["y"]+x;
    newObject /: newObject.function2[x_] := 2 newObject["y"]+x;

    newObject
  ];

Les propriétés sont stockées en tant que DownValues ​​et les méthodes en tant que Upvalues ​​retardées dans le symbole créé par Module qui est renvoyé. J'ai trouvé la syntaxe de function2 qui est la syntaxe OO habituelle pour les fonctions de la structure de données arborescente dans Mathematica .

Pour une liste des types de valeurs existants de chaque symbole, voir http://reference.wolfram.com/mathematica/tutorial/PatternsAndTransformationRules.html et http://www.verbeia.com/mathematica/tips/HTMLLinks/Tricks_Misc_4.html .

Par exemple, essayez ceci

x = NewObject[y -> 3];
function[x, 4]
x.function2[5]

Vous pouvez aller plus loin si vous souhaitez émuler l'héritage d'objets à l'aide d'un package appelé InheritRules disponible ici http://library.wolfram.com/infocenter/MathSource/671/

Vous pouvez également stocker la définition de la fonction non pas dans newObject mais dans un symbole de type, donc si NewObject a renvoyé le type [newObject] au lieu de newObject, vous pouvez définir la fonction et la fonction2 comme ceci en dehors de NewObject (et pas à l'intérieur) et avoir la même utilisation qu'avant .

function[type[object_], x_] ^:= object["y"] + x;
type /: type[object_].function2[x_] := 2 object["y"]+x;

Utilisez UpValues ​​[type] pour voir que la fonction et la fonction2 sont définies dans le symbole de type.

D'autres idées sur cette dernière syntaxe sont présentées ici https://mathematica.stackexchange.com/a/999/66 .

Version améliorée de SelectEquivalents

@rcollyer: Merci beaucoup d'avoir apporté SelectEquivalents à la surface, c'est une fonction incroyable. Voici une version améliorée de SelectEquivalents listée ci-dessus avec plus de possibilités et utilisant des options, cela le rend plus facile à utiliser.

Options[SelectEquivalents] = 
   {
      TagElement->Identity,
      TransformElement->Identity,
      TransformResults->(#2&) (*#1=tag,#2 list of elements corresponding to tag*),
      MapLevel->1,
      TagPattern->_,
      FinalFunction->Identity
   };

SelectEquivalents[x_List,OptionsPattern[]] := 
   With[
      {
         tagElement=OptionValue@TagElement,
         transformElement=OptionValue@TransformElement,
         transformResults=OptionValue@TransformResults,
         mapLevel=OptionValue@MapLevel,
         tagPattern=OptionValue@TagPattern,
         finalFunction=OptionValue@FinalFunction
      }
      ,
      finalFunction[
         Reap[
            Map[
               Sow[
                  transformElement@#
                  ,
                  {tagElement@#}
               ]&
               , 
               x
               , 
               {mapLevel}
            ] 
            , 
            tagPattern
            , 
            transformResults
         ][[2]]
      ]
   ];

Voici des exemples d'utilisation de cette version:

Utiliser correctement Mathematica Gather / Collect

Comment feriez-vous une fonction de tableau croisé dynamique dans Mathematica?

Algorithme de binning 2D rapide Mathematica

Interne`Sac

Daniel Lichtblau décrit ici une structure de données interne intéressante pour la croissance des listes.

Implémentation d'un Quadtree dans Mathematica

Fonctions de débogage

Ces deux articles pointent vers des fonctions utiles pour le débogage:

Comment déboguer lors de l'écriture de petits ou gros codes avec Mathematica? Table de travail? débogueur mma? ou autre chose? (Montre le)

/programming/5459735/the-clearest-way-to-represent-mathematicas-evaluation-sequence/5527117#5527117 (TraceView)

Voici une autre fonction basée sur Reap et Sow pour extraire des expressions de différentes parties d'un programme et les stocker dans un symbole.

SetAttributes[ReapTags,HoldFirst];
ReapTags[expr_]:=
   Module[{elements},
      Reap[expr,_,(elements[#1]=#2/.{x_}:>x)&];
      elements
   ];

Voici un exemple

ftest[]:=((*some code*)Sow[1,"x"];(*some code*)Sow[2,"x"];(*some code*)Sow[3,"y"]);
s=ReapTags[ftest[]];
Keys[s]
s["x"]
PrintSymbol[s] (*Keys and PrintSymbol are defined above*)

Autres ressources

Voici une liste de liens intéressants à des fins d'apprentissage:

Une collection de ressources d'apprentissage Mathematica

Mis à jour ici: https://mathematica.stackexchange.com/a/259/66


Connexes: " La meilleure façon de construire une fonction avec mémoire ". WReach y a donné un exemple étonnant de fonction simple qui non seulement se souvient de ses valeurs, mais les écrit également dans un fichier et lit en arrière au redémarrage.
Alexey Popkov

1
Connexes: " Mathematica: Comment vider le cache pour un symbole, c'est-à-dire Unset sans motif DownValues ". Cette question montre comment vider le cache à l'aide de la f[x_] := f[x] = some codemémorisation standard .
Simon

7
1 Il est bien pratique qui notationnelle élimine la nécessité de répéter le côté gauche de la définition d'une fonction de mise en cache, par exemple: c:Cache[expr_] := c = expr.
WReach

Belle variante de SelectEquivalents. Je pense que je resterais TagOnElementle deuxième paramètre par défaut, Identitycar c'est le plus utilisé d'entre eux. Je ne pense pas avoir inclus FinalOpnon plus, car cela peut être traité à l'intérieur OpOnTaggedElems. Je raccourcirais également les noms des options, car leur longueur rend la saisie difficile. Essayez TagFunction, TransformElement, TransformResultset à la TagPatternplace. Les deux, TagPatternet MapLevelsont d'excellents ajouts à la fonctionnalité, et une bonne réécriture, dans l'ensemble.
rcollyer

Merci pour ton commentaire rcollyer. Je l'ai pris en compte et amélioré également la lisibilité du code. Je garde FinalFunction car il opère sur le résultat de Reap, par exemple si vous souhaitez trier votre résultat final par balises si vous les conservez.
faysou

12

Mes fonctions utilitaires (je les ai intégrées à MASH, ce qui est mentionné dans la question):

pr = WriteString["stdout", ##]&;            (* More                           *)
prn = pr[##, "\n"]&;                        (*  convenient                    *)
perr = WriteString["stderr", ##]&;          (*   print                        *)
perrn = perr[##, "\n"]&;                    (*    statements.                 *)
re = RegularExpression;                     (* I wish mathematica             *)
eval = ToExpression[cat[##]]&;              (*  weren't so damn               *)
EOF = EndOfFile;                            (*   verbose!                     *)
read[] := InputString[""];                  (* Grab a line from stdin.        *)
doList[f_, test_] :=                        (* Accumulate list of what f[]    *)
  Most@NestWhileList[f[]&, f[], test];      (*  returns while test is true.   *)
readList[] := doList[read, #=!=EOF&];       (* Slurp list'o'lines from stdin. *)
cat = StringJoin@@(ToString/@{##})&;        (* Like sprintf/strout in C/C++.  *)
system = Run@cat@##&;                       (* System call.                   *)
backtick = Import[cat["!", ##], "Text"]&;   (* System call; returns stdout.   *)
slurp = Import[#, "Text"]&;                 (* Fetch contents of file as str. *)
                                            (* ABOVE: mma-scripting related.  *)
keys[f_, i_:1] :=                           (* BELOW: general utilities.      *)
  DownValues[f, Sort->False][[All,1,1,i]];  (* Keys of a hash/dictionary.     *)
SetAttributes[each, HoldAll];               (* each[pattern, list, body]      *)
each[pat_, lst_, bod_] := ReleaseHold[      (*  converts pattern to body for  *)
  Hold[Cases[Evaluate@lst, pat:>bod];]];    (*   each element of list.        *)
some[f_, l_List] := True ===                (* Whether f applied to some      *)
  Scan[If[f[#], Return[True]]&, l];         (*  element of list is True.      *)
every[f_, l_List] := Null ===               (* Similarly, And @@ f/@l         *)
  Scan[If[!f[#], Return[False]]&, l];       (*  (but with lazy evaluation).   *)


11

Une astuce que j'ai utilisée, qui vous permet d'émuler la façon dont la plupart des fonctions intégrées fonctionnent avec de mauvais arguments (en envoyant un message puis en renvoyant le formulaire entier non évalué) exploite une bizarrerie de la façon dont Conditionfonctionne lorsqu'il est utilisé dans une définition. Si cela foone devrait fonctionner qu'avec un seul argument:

foo[x_] := x + 1;
expr : foo[___] /; (Message[foo::argx, foo, Length@Unevaluated[expr], 1]; 
                    False) := Null; (* never reached *)

Si vous avez des besoins plus complexes, il est facile de considérer la validation des arguments et la génération de messages comme une fonction indépendante. Vous pouvez faire des choses plus élaborées en utilisant des effets secondairesCondition delà de la simple génération de messages, mais à mon avis, la plupart d'entre eux tombent dans la catégorie "bidouillage" et devraient être évités si possible.

De plus, dans la catégorie "métaprogrammation", si vous avez un .mfichier package Mathematica ( ), vous pouvez utiliser l' "HeldExpressions"élément pour récupérer toutes les expressions du fichier encapsulées HoldComplete. Cela rend le suivi des choses beaucoup plus facile que d'utiliser des recherches textuelles. Malheureusement, il n'y a pas de moyen facile de faire la même chose avec un bloc-notes, mais vous pouvez obtenir toutes les expressions d'entrée en utilisant quelque chose comme ce qui suit:

inputExpressionsFromNotebookFile[nb_String] :=
 Cases[Get[nb],
  Cell[BoxData[boxes_], "Input", ___] :>
   MakeExpression[StripBoxes[boxes], StandardForm],
  Infinity]

Enfin, vous pouvez utiliser le fait qui Moduleémule les fermetures lexicales pour créer l'équivalent des types référence. Voici une pile simple (qui utilise une variante de l' Conditionastuce pour la gestion des erreurs en prime):

ClearAll[MakeStack, StackInstance, EmptyQ, Pop, Push, Peek]
 With[{emptyStack = Unique["empty"]},
  Attributes[StackInstance] = HoldFirst;
  MakeStack[] :=
   Module[{backing = emptyStack},
    StackInstance[backing]];

  StackInstance::empty = "stack is empty";

  EmptyQ[StackInstance[backing_]] := (backing === emptyStack);

  HoldPattern[
    Pop[instance : StackInstance[backing_]]] /;
    ! EmptyQ[instance] || (Message[StackInstance::empty]; False) :=
   (backing = Last@backing; instance);

  HoldPattern[Push[instance : StackInstance[backing_], new_]] :=
   (backing = {new, backing}; instance);

  HoldPattern[Peek[instance : StackInstance[backing_]]] /;
    ! EmptyQ[instance] || (Message[StackInstance::empty]; False) :=
   First@backing]

Vous pouvez désormais imprimer les éléments d'une liste dans l'ordre inverse d'une manière inutilement compliquée!

With[{stack = MakeStack[], list},
 Do[Push[stack, elt], {elt, list}];

 While[!EmptyQ[stack],
  Print[Peek@stack];
  Pop@stack]]

1
+1 pour l' HeldExpressionsélément dans les packages, n'en était pas conscient. J'importais généralement sous forme de chaîne, puis j'utilisais ToExpressionavec HoldCompletecomme dernier argument. En ce qui concerne l'utilisation Conditiondes messages - c'est une technique standard dans l'écriture de paquets depuis au moins 1994. Concernant la persistance via Modulevars - j'ai eu un long article à ce sujet sur Mathgroup il y a quelque temps: groups.google.com/group/comp.soft- sys.math.mathematica /… (mon troisième article dans ce fil de discussion), cela va dans le même sens et contient des liens vers quelques exemples d'utilisation non triviaux.
Leonid Shifrin

@Leonid Shifrin: J'ai repris le Conditiontruc comme un savoir, probablement d'un collègue, mais je ne savais pas que c'était une technique standard. Le lien sur l'utilisation des Modulesymboles comme types de référence est intéressant!
Pillsy

+1, je n'y ai jamais pensé. Plus j'en apprends sur ce langage, plus il semble puissant.
rcollyer

@Pillsy quel est le but de faire une pile de cette façon?
Mr.Wizard

@ Mr.Wizard: Je viens de choisir l'une des structures de données mutables les plus simples auxquelles je puisse penser pour illustrer la technique.
Pillsy

11

Impression des définitions de symboles du système sans contexte ajouté

La contextFreeDefinition[]fonction ci-dessous tentera d'imprimer la définition d'un symbole sans le contexte le plus courant ajouté. La définition peut ensuite être copiée dans Workbench et formatée pour la lisibilité (sélectionnez-la, clic droit, Source -> Format)

Clear[commonestContexts, contextFreeDefinition]

commonestContexts[sym_Symbol, n_: 1] := Quiet[
  Commonest[
   Cases[Level[DownValues[sym], {-1}, HoldComplete], 
    s_Symbol /; FreeQ[$ContextPath, Context[s]] :> Context[s]], n],
  Commonest::dstlms]

contextFreeDefinition::contexts = "Not showing the following contexts: `1`";

contextFreeDefinition[sym_Symbol, contexts_List] := 
 (If[contexts =!= {}, Message[contextFreeDefinition::contexts, contexts]];
  Internal`InheritedBlock[{sym}, ClearAttributes[sym, ReadProtected];
   Block[{$ContextPath = Join[$ContextPath, contexts]}, 
    Print@InputForm[FullDefinition[sym]]]])

contextFreeDefinition[sym_Symbol, context_String] := 
 contextFreeDefinition[sym, {context}]

contextFreeDefinition[sym_Symbol] := 
 contextFreeDefinition[sym, commonestContexts[sym]]

withRules []

Avertissement: cette fonction ne localise pas les variables de la même manière Withet Modulene le fait pas, ce qui signifie que les constructions de localisation imbriquées ne fonctionneront pas comme prévu. withRules[{a -> 1, b -> 2}, With[{a=3}, b_ :> b]] va remplacer aet bdans le imbriquée Withet Rule, alors queWith en ne le fait pas.

Ceci est une variante de Withqui utilise des règles au lieu de =et :=:

ClearAll[withRules]
SetAttributes[withRules, HoldAll]
withRules[rules_, expr_] :=
  Internal`InheritedBlock[
    {Rule, RuleDelayed},
    SetAttributes[{Rule, RuleDelayed}, HoldFirst];
    Unevaluated[expr] /. rules
  ]

J'ai trouvé cela utile lors du nettoyage du code écrit pendant l'expérimentation et la localisation des variables. Parfois, je me retrouve avec des listes de paramètres sous la forme de {par1 -> 1.1, par2 -> 2.2}. Les withRulesvaleurs de paramètre sont faciles à injecter dans le code précédemment écrit à l'aide de variables globales.

L'utilisation est juste comme With:

withRules[
  {a -> 1, b -> 2},
  a+b
]

Graphiques 3D anti-crénelage

Il s'agit d'une technique très simple pour antialiaser les graphiques 3D même si votre matériel graphique ne le prend pas en charge de manière native.

antialias[g_, n_: 3] := 
  ImageResize[Rasterize[g, "Image", ImageResolution -> n 72], Scaled[1/n]]

Voici un exemple:

Graphiques Mathematica Graphiques Mathematica

Notez qu'une valeur élevée nou une taille d'image élevée a tendance à exposer des bogues de pilotes graphiques ou à introduire des artefacts.


Fonctionnalité de diff du notebook

La fonctionnalité Notebook diff est disponible dans le <<AuthorTools`package et (au moins dans la version 8) dans le NotebookTools`contexte non documenté . C'est une petite interface graphique pour différencier deux notebooks actuellement ouverts:

PaletteNotebook@DynamicModule[
  {nb1, nb2}, 
  Dynamic@Column[
    {PopupMenu[Dynamic[nb1], 
      Thread[Notebooks[] -> NotebookTools`NotebookName /@ Notebooks[]]], 
     PopupMenu[Dynamic[nb2], 
      Thread[Notebooks[] -> NotebookTools`NotebookName /@ Notebooks[]]], 
     Button["Show differences", 
      CreateDocument@NotebookTools`NotebookDiff[nb1, nb2]]}]
  ]

Graphiques Mathematica


Tout serait bien, mais cela ne localise pas vraiment les variables, comme vous pouvez le voir en attribuant say a = 3; b = 4;avant votre exemple d'appel, puis en appelant withRules. Vous pouvez l' enregistrer en utilisant plutôt ce qui suit: SetAttributes[withRules, HoldAll];withRules[rules_, expr_] := Unevaluated[expr] /. Unevaluated[rules]. Les différences de sémantique d' Withalors: 1. les côtés des règles ne sont pas évalués maintenant 2. withRulesne résout pas les conflits de dénomination avec les constructions de portée interne comme le Withfait. Le dernier est assez sérieux - être une bonne ou une mauvaise chose selon les cas.
Leonid Shifrin

@Leonid Vous avez tout à fait raison, il semble que je n'apprenne jamais à vérifier correctement le code avant de poster ... quand j'utilise cela, je n'attribue pratiquement jamais de valeurs aux variables, mais c'est un problème assez sérieux, vous avez raison. Que pensez-vous de la version corrigée? (Je ne me soucie pas vraiment de ne pas gérer les Withs imbriqués . Cela ne fonctionne pas toujours non plus avec les constructions de localisation intégrées, par exemple With[{a=1}, Block[{a=2}, a]]. Pensez-vous qu'il y ait une bonne raison pour laquelle l'imbrication Blockne se localise pas là, comme imbriqué Withet le Modulefait?)
Szabolcs

@Leonid Je n'ai pas simplement utilisé Unevaluated[rules]parce que je voulais x -> 1+1évaluer le RHS.
Szabolcs

@Leonid Vous avez en fait raison, le problème de localisation imbriquée peut être assez sérieux. Je pense que les Withs imbriqués sont faciles à repérer et à éviter, mais les modèles ne le sont pas: With[{a = 1}, a_ -> a]localise l'intérieur aalors que ce withRulesn'est pas le cas. Savez-vous s'il existe un moyen d'accéder au mécanisme de localisation interne de Mathematica et de créer de nouvelles constructions (similaires à Rule) qui localisent également? Je supprimerai probablement cette réponse plus tard car elle est plus dangereuse qu'utile, mais j'aimerais d'abord jouer un peu plus avec elle.
Szabolcs

Je pense que votre utilisation de InheritedBlockest plutôt cool et résout le problème de manière très élégante. En ce qui concerne les conflits de portée, normalement les liaisons pour la portée lexicale se produisent au "moment de la liaison lexicale", c'est-à-dire avant l'exécution, tandis que la portée dynamique se lie au moment de l'exécution, ce qui pourrait l'expliquer. Vous pouvez comparer cela avec le cas similaire pour Module, qui permet une utilisation constructive (voir par exemple ici stackoverflow.com/questions/7394113/… ). Le problème est qu'il Blockfaut un symbole pour ...
Leonid Shifrin

9

Les fonctions pures récursives ( #0) semblent être l'un des coins les plus sombres du langage. Voici quelques exemples non triviaux de leur utilisation, où cela est vraiment utile (non pas qu'ils ne peuvent pas se passer de cela). Ce qui suit est une fonction assez concise et raisonnablement rapide pour trouver des composants connectés dans un graphe, étant donné une liste d'arêtes spécifiées sous forme de paires de sommets:

ClearAll[setNew, componentsBFLS];
setNew[x_, x_] := Null;
setNew[lhs_, rhs_]:=lhs:=Function[Null, (#1 := #0[##]); #2, HoldFirst][lhs, rhs];

componentsBFLS[lst_List] := Module[{f}, setNew @@@ Map[f, lst, {2}];
   GatherBy[Tally[Flatten@lst][[All, 1]], f]];

Ce qui se passe ici, c'est que nous mappons d'abord un symbole factice sur chacun des nombres de sommets, puis mettons en place une manière qui, étant donné une paire de sommets {f[5],f[10]}, par exemple, f[5]serait alors évaluée f[10]. La fonction pure récursive est utilisée comme compresseur de chemin (pour configurer la mémorisation de telle sorte qu'au lieu de longues chaînes comme f[1]=f[3],f[3]=f[4],f[4]=f[2], ..., les valeurs mémorisées soient corrigées chaque fois qu'une nouvelle "racine" du composant est découverte. Cela donne une accélération significative. Parce que nous utilisons l'affectation, nous avons besoin qu'elle soit HoldAll, ce qui rend cette construction encore plus obscure et plus attrayante). Cette fonction est le résultat d'une discussion en ligne et hors ligne de Mathgroup impliquant Fred Simons, Szabolcs Horvat, DrMajorBob et le vôtre. Exemple:

In[13]:= largeTest=RandomInteger[{1,80000},{40000,2}];

In[14]:= componentsBFLS[largeTest]//Short//Timing
Out[14]= {0.828,{{33686,62711,64315,11760,35384,45604,10212,52552,63986,  
     <<8>>,40962,7294,63002,38018,46533,26503,43515,73143,5932},<<10522>>}}

Il est certes beaucoup plus lent qu'un intégré, mais pour la taille du code, assez rapide quand même IMO.

Autre exemple: voici une réalisation récursive de Select, basée sur des listes chaînées et des fonctions pures récursives:

selLLNaive[x_List, test_] :=
  Flatten[If[TrueQ[test[#1]],
     {#1, If[#2 === {}, {}, #0 @@ #2]},
     If[#2 === {}, {}, #0 @@ #2]] & @@ Fold[{#2, #1} &, {}, Reverse[x]]];

Par exemple,

In[5]:= Block[
         {$RecursionLimit= Infinity},
         selLLNaive[Range[3000],EvenQ]]//Short//Timing

Out[5]= {0.047,{2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,
 <<1470>>,2972,2974,2976,2978,2980,2982,2984,2986,2988,2990,
  2992,2994,2996,2998,3000}}

Il n'est cependant pas correctement récursif de queue, et fera exploser la pile (plantera le noyau) pour des listes plus grandes. Voici la version récursive de la queue:

selLLTailRec[x_List, test_] :=
Flatten[
 If[Last[#1] === {},
  If[TrueQ[test[First[#1]]],
   {#2, First[#1]}, #2],
  (* else *)
  #0[Last[#1],
   If[TrueQ[test[First[#1]]], {#2, First[#1]}, #2]
   ]] &[Fold[{#2, #1} &, {}, Reverse[x]], {}]];

Par exemple,

In[6]:= Block[{$IterationLimit= Infinity},
       selLLTailRec[Range[500000],EvenQ]]//Short//Timing
Out[6]= {2.39,{2,4,6,8,10,12,14,16,18,20,22,
       <<249978>>,499980,499982,499984,499986,499988,499990,499992,
        499994,499996,499998,500000}} 

La fonction pour les composants connectés est toujours une de mes préférées :-)
Szabolcs

@Szabolcs Oui, c'est plutôt cool. Vous et Fred avez fait l'essentiel, Bobby et moi n'avons ajouté que quelques améliorations, IIRC.
Leonid Shifrin

8

Ceci est la recette du livre de Stan Wagon ... utilisez-la lorsque le Plot intégré se comporte de manière erratique en raison d'un manque de précision

Options[PrecisePlot] = {PrecisionGoal -> 6};
PrecisePlot[f_, {x_, a_, b_}, opts___] := Module[{g, pg},
   pg = PrecisionGoal /. {opts} /. Options[PrecisePlot];
   SetAttributes[g, NumericFunction];
   g[z_?InexactNumberQ] := Evaluate[f /. x -> z];
   Plot[N[g[SetPrecision[y, \[Infinity]]], pg], {y, a, b},
    Evaluate[Sequence @@ FilterRules[{opts}, Options[Plot]]]]];

J'utilise souvent l'astuce suivante de Kristjan Kannike lorsque j'ai besoin d'un comportement "de type dictionnaire" à partir des valeurs descendantes de Mathematica

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];

(* Usage example: *)
(* Count number of times each subexpression occurs in an expression *)
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]

Lorsque les résultats de l'évaluation sont confus, il est parfois utile de vider les étapes d'évaluation dans un fichier texte

SetAttributes[recordSteps, HoldAll];
recordSteps[expr_] :=
 Block[{$Output = List@OpenWrite["~/temp/msgStream.m"]}, 
  TracePrint[Unevaluated[expr], _?(FreeQ[#, Off] &), 
   TraceInternal -> True];
  Close /@ $Output;
  Thread[Union@
    Cases[ReadList["~/temp/msgStream.m", HoldComplete[Expression]], 
     symb_Symbol /; 
       AtomQ@Unevaluated@symb && 
        Context@Unevaluated@symb === "System`" :> 
      HoldComplete@symb, {0, Infinity}, Heads -> True], HoldComplete]
  ]

(* Usage example: *)
(* puts steps of evaluation of 1+2+Sin[5]) into ~/temp/msgStream.m *)
recordSteps[1+2+Sin[5]]

Un échantillon d'utilisation serait génial. Essayez d'en publier un lorsque vous en avez le temps.
Dr. belisarius

Connaissez-vous Kristjan? J'avais l'habitude de travailler dans le même groupe avec lui à Helsinki. Gentil gars, petit monde.
Timo

Non, a trouvé son code sur le web. En fait, j'ai essayé de lui envoyer un e-mail pour corriger un petit bogue dans le code, mais l'e-mail sur sa page Web ne fonctionne plus
Yaroslav Bulatov

8

Il est possible d'exécuter MathKernel en mode batch en utilisant des options de ligne de commande-batchinput-batchoutput non documentées et :

math -batchinput -batchoutput < input.m > outputfile.txt

(où input.mest le fichier d'entrée par lots se terminant par le caractère de nouvelle ligne, outputfile.txtest le fichier vers lequel la sortie sera redirigée).

Dans Mathematica v.> = 6, MathKernel a une option de ligne de commande non documentée:

-noicon

qui contrôle si MathKernel aura une icône visible sur la barre des tâches (au moins sous Windows).

Le FrontEnd (au moins à partir de la version 5) a une option de ligne de commande non documentée

-b

qui désactive l'écran de démarrage et permet d'exécuter le Mathematica FrontEnd beaucoup plus rapidement

et option

-directlaunch

qui désactive le mécanisme qui lance la version la plus récente de Mathematica installée au lieu de lancer la version associée aux fichiers .nb dans le registre système.

Une autre façon de le faire est probablement :

Au lieu de lancer le binaire Mathematica.exe dans le répertoire d'installation, lancez le binaire Mathematica.exe dans SystemFiles \ FrontEnd \ Binaries \ Windows. Le premier est un simple programme de lancement qui fait de son mieux pour rediriger les demandes d'ouverture de blocs-notes vers des copies en cours d'exécution de l'interface utilisateur. Ce dernier est le binaire de l'interface utilisateur lui-même.

Il est pratique de combiner la dernière option de ligne de commande avec la définition de l'option FrontEnd globale VersionedPreferences->True qui désactive le partage des préférences entre les différentes versions de Mathematica installées :

SetOptions[$FrontEnd, VersionedPreferences -> True]

(Ce qui précède doit être évalué dans la version la plus récente de Mathematica installée.)

Dans Mathematica 8, cela est contrôlé dans la boîte de dialogue Préférences, dans le volet Système, sous le paramètre "Créer et maintenir des préférences frontales spécifiques à la version" .

Il est possible d'obtenir une liste incomplète des options de ligne de commande du FrontEnd en utilisant une clé non documentée -h(le code pour Windows):

SetDirectory[$InstallationDirectory <> 
   "\\SystemFiles\\FrontEnd\\Binaries\\Windows\\"];
Import["!Mathematica -h", "Text"]

donne:

Usage:  Mathematica [options] [files]
Valid options:
    -h (--help):  prints help message
    -cleanStart (--cleanStart):  removes existing preferences upon startup
    -clean (--clean):  removes existing preferences upon startup
    -nogui (--nogui):  starts in a mode which is initially hidden
    -server (--server):  starts in a mode which disables user interaction
    -activate (--activate):  makes application frontmost upon startup
    -topDirectory (--topDirectory):  specifies the directory to search for resources and initialization files
    -preferencesDirectory (--preferencesDirectory):  specifies the directory to search for user AddOns and preference files
    -password (--password):  specifies the password contents
    -pwfile (--pwfile):  specifies the path for the password file
    -pwpath (--pwpath):  specifies the directory to search for the password file
    -b (--b):  launches without the splash screen
    -min (--min):  launches as minimized

D'autres options incluent:

-directLaunch:  force this FE to start
-32:  force the 32-bit FE to start
-matchingkernel:  sets the frontend to use the kernel of matching bitness
-Embedding:  specifies that this instance is being used to host content out of process

Existe-t-il d'autres options de ligne de commande potentiellement utiles de MathKernel et de FrontEnd? Veuillez partager si vous savez.

Question connexe .


"correspondant bitness?" Qu'est-ce que ça veut dire?
Mr.Wizard

@ Mr.Wizard Probablement cette option n'a de sens que sous les systèmes 64 bits en combinaison avec l'option -32et signifie que le bitness du MathKernel utilisé par le FrontEnd correspondra au bitness du système d'exploitation (64 bits). Il semble que dans d'autres cas, cette option ne changera rien.
Alexey Popkov

7

Mes hacks préférés sont de petites macros générant du code qui vous permettent de remplacer un tas de commandes standard standard par une courte. Vous pouvez également créer des commandes pour ouvrir / créer des blocs-notes.

Voici ce que j'utilise depuis un certain temps dans mon flux de travail Mathematica quotidien. Je me suis retrouvé à jouer beaucoup ce qui suit:

  1. Faire en sorte qu'un notebook ait un contexte privé, charger le (s) package (s) dont j'ai besoin, le sauvegarder automatiquement.
  2. Après avoir travaillé avec ce cahier pendant un certain temps, je voudrais faire quelques calculs de scratch dans un cahier séparé, avec son propre contexte privé, tout en ayant accès aux définitions que j'utilise dans le cahier "principal". Parce que j'ai configuré le contexte privé, cela nécessite d'ajuster manuellement $ ContextPath

Faire tout cela à la main encore et encore est une douleur, alors automatisons! Tout d'abord, un code utilitaire:

(* Credit goes to Sasha for SelfDestruct[] *)
SetAttributes[SelfDestruct, HoldAllComplete];
SelfDestruct[e_] := (If[$FrontEnd =!= $Failed,
   SelectionMove[EvaluationNotebook[], All, EvaluationCell]; 
   NotebookDelete[]]; e)

writeAndEval[nb_,boxExpr_]:=(
    NotebookWrite[nb,  CellGroupData[{Cell[BoxData[boxExpr],"Input"]}]];
    SelectionMove[nb, Previous, Cell]; 
    SelectionMove[nb, Next, Cell];
    SelectionEvaluate[nb];
)

ExposeContexts::badargs = 
  "Exposed contexts should be given as a list of strings.";
ExposeContexts[list___] := 
 Module[{ctList}, ctList = Flatten@List@list; 
  If[! MemberQ[ctList, Except[_String]],AppendTo[$ContextPath, #] & /@ ctList, 
   Message[ExposeContexts::badargs]];
  $ContextPath = DeleteDuplicates[$ContextPath];
  $ContextPath]

    Autosave[x:(True|False)] := SetOptions[EvaluationNotebook[],NotebookAutoSave->x];

Maintenant, créons une macro qui va mettre les cellules suivantes dans le cahier:

SetOptions[EvaluationNotebook[], CellContext -> Notebook]
Needs["LVAutils`"]
Autosave[True]

Et voici la macro:

MyPrivatize[exposedCtxts : ({__String} | Null) : Null]:=
  SelfDestruct@Module[{contBox,lvaBox,expCtxtBox,assembledStatements,strList},
    contBox = MakeBoxes[SetOptions[EvaluationNotebook[], CellContext -> Notebook]];
    lvaBox = MakeBoxes[Needs["LVAutils`"]];

    assembledStatements = {lvaBox,MakeBoxes[Autosave[True]],"(*********)"};
    assembledStatements = Riffle[assembledStatements,"\[IndentingNewLine]"]//RowBox;
    writeAndEval[InputNotebook[],contBox];
    writeAndEval[InputNotebook[],assembledStatements];
    If[exposedCtxts =!= Null,
       strList = Riffle[("\"" <> # <> "\"") & /@ exposedCtxts, ","];
       expCtxtBox = RowBox[{"ExposeContexts", "[", RowBox[{"{", RowBox[strList], "}"}], "]"}];
       writeAndEval[InputNotebook[],expCtxtBox];
      ]
 ]

Maintenant, lorsque je tape, MyPrivatize[]c'est crée le contexte privé et charge mon package standard. Créons maintenant une commande qui ouvrira un nouveau bloc-notes avec son propre contexte privé (pour que vous puissiez y pirater avec un abandon sauvage sans risquer de bousiller les définitions), mais qui a accès à vos contextes actuels.

SpawnScratch[] := SelfDestruct@Module[{nb,boxExpr,strList},
    strList = Riffle[("\"" <> # <> "\"") & /@ $ContextPath, ","];
    boxExpr = RowBox[{"MyPrivatize", "[",
        RowBox[{"{", RowBox[strList], "}"}], "]"}];
    nb = CreateDocument[];
    writeAndEval[nb,boxExpr];
]

La chose intéressante à ce sujet est que SelfDestruct, lorsque la commande s'exécute, elle ne laisse aucune trace dans le cahier actuel - ce qui est bien, car sinon, cela créerait simplement du désordre.

Pour des points de style supplémentaires, vous pouvez créer des déclencheurs de mots clés pour ces macros en utilisant InputAutoReplacements, mais je laisserai cela comme un exercice pour le lecteur.


7

PutAppend avec PageWidth -> Infinity

Dans Mathematica, l' utilisation de la PutAppendcommande est le moyen le plus simple de maintenir un fichier journal en cours d'exécution avec les résultats des calculs intermédiaires. Mais il utilise par défaut le PageWith->78paramètre lors de l'exportation d'expressions vers un fichier et il n'y a donc aucune garantie que chaque sortie intermédiaire ne prendra qu'une seule ligne dans le journal.

PutAppendn'a pas d'options en lui-même mais le suivi de ses évaluations révèle qu'il est basé sur la OpenAppendfonction qui a l' PageWithoption et permet de changer sa valeur par défaut par la SetOptionscommande:

In[2]:= Trace[x>>>"log.txt",TraceInternal->True]
Out[2]= {x>>>log.txt,{OpenAppend[log.txt,CharacterEncoding->PrintableASCII],OutputStream[log.txt,15]},Null}

Nous pouvons PutAppenddonc ajouter une seule ligne à la fois en définissant:

SetOptions[OpenAppend, PageWidth -> Infinity]

METTRE À JOUR

Il y a un bug introduit dans la version 10 (corrigé dans la version 11.3): SetOptionsn'affecte plus le comportement de OpenWriteet OpenAppend.

Une solution de contournement consiste à implémenter votre propre version de PutAppendavec l' PageWidth -> Infinityoption explicite :

Clear[myPutAppend]
myPutAppend[expr_, pathtofile_String] :=
 (Write[#, expr]; Close[#];) &[OpenAppend[pathtofile, PageWidth -> Infinity]]

Notez que nous pouvons également l'implémenter via WriteStringcomme indiqué dans cette réponse, mais dans ce cas, il sera nécessaire de convertir au préalable l'expression en InputFormvia correspondant ToString[expr, InputForm].


6

Je regardais à travers l' un de mes paquets pour l' inclusion dans ce domaine , et a trouvé quelques messages que je définis qui font des merveilles: Debug::<some name>. Par défaut, ils sont désactivés, donc ne produisent pas beaucoup de frais généraux. Mais, je peux jeter mon code avec eux, et les activer si j'ai besoin de comprendre exactement comment un peu de code se comporte.


Depuis l'aide> Depuis la version 2.0 (sortie en 1991), Debug a été remplacé par Trace.
Dr. belisarius

1
@belisarius, vous avez manqué le point. Ce n'est ni les fonctions Debugni Trace; c'est un ensemble de messages que j'ai créés avec lesquels je peux jeter mon code pour activer / désactiver à volonté. Ils sont précédés du mot Debug, de la même manière qu'un usagemsg est précédé du nom de la fonction. Il fournit la même fonctionnalité que de placer un tas d' coutinstructions dans du code C ++.
rcollyer

1
Ohh ... désolé. Je suis confus parce que je n'ai jamais été diplômé de la maternelle pour ne pas avoir appris "Les capitales sont pour les pays": D
Dr. belisarius

6

L'une des choses qui me dérange à propos des constructions de portée intégrées est qu'elles évaluent toutes les définitions de variables locales à la fois, vous ne pouvez donc pas écrire par exemple

With[{a = 5, b = 2 * a},
    ...
]

Donc, il y a quelque temps, j'ai proposé une macro appelée WithNest qui vous permet de le faire. Je trouve cela pratique, car il vous permet de garder les liaisons de variables locales sans avoir à faire quelque chose comme

Module[{a = 5,b},
    b = 2 * a;
    ...
]

En fin de compte, le meilleur moyen que j'ai pu trouver pour le faire était d'utiliser un symbole spécial pour faciliter la répétition de la liste des liaisons, et j'ai mis la définition dans son propre package pour garder ce symbole caché. Peut-être que quelqu'un a une solution plus simple à ce problème?

Si vous voulez l'essayer, placez ce qui suit dans un fichier appelé Scoping.m:

BeginPackage["Scoping`"];

WithNest::usage=
"WithNest[{var1=val1,var2=val2,...},body] works just like With, except that
values are evaluated in order and later values have access to earlier ones.
For example, val2 can use var1 in its definition.";

Begin["`Private`"];

(* Set up a custom symbol that works just like Hold. *)
SetAttributes[WithNestHold,HoldAll];

(* The user-facing call.  Give a list of bindings and a body that's not
our custom symbol, and we start a recursive call by using the custom
symbol. *)
WithNest[bindings_List,body:Except[_WithNestHold]]:=
WithNest[bindings,WithNestHold[body]];

(* Base case of recursive definition *)
WithNest[{},WithNestHold[body_]]:=body;

WithNest[{bindings___,a_},WithNestHold[body_]]:=
WithNest[
{bindings},
WithNestHold[With[List@a,body]]];

SyntaxInformation[WithNest]={"ArgumentsPattern"->{{__},_}};
SetAttributes[WithNest,{HoldAll,Protected}];

End[];

EndPackage[];

Janus a publié une version de ceci, et référence votre question sur MathGroup: stackoverflow.com/questions/4190845/custom-notation-question
...

Merci d'avoir fait remarquer cela! Cela fait un moment que je n'ai pas regardé ce truc, et c'est intéressant de voir toutes ces autres approches.
DGrady

5

Celui-ci a été écrit par Alberto Di Lullo, (qui ne semble pas être sur Stack Overflow).

CopyToClipboard, pour Mathematica 7 (dans Mathematica 8, il est intégré)

CopyToClipboard[expr_] := 
  Module[{nb}, 
   nb = CreateDocument[Null, Visible -> False, WindowSelected -> True];
   NotebookWrite[nb, Cell[OutputFormData@expr], All];
   FrontEndExecute[FrontEndToken[nb, "Copy"]];
   NotebookClose@nb];

Message original: http://forums.wolfram.com/mathgroup/archive/2010/Jun/msg00148.html

J'ai trouvé cette routine utile pour copier de grands nombres réels dans le presse-papiers sous forme décimale ordinaire. Par exempleCopyToClipboard["123456789.12345"]

Cell[OutputFormData@expr] supprime proprement les guillemets.


5

Ce code crée une palette qui télécharge la sélection dans Stack Exchange en tant qu'image. Sous Windows, un bouton supplémentaire est fourni qui donne un rendu plus fidèle de la sélection.

Copiez le code dans une cellule de cahier et évaluez. Ensuite, sortez la palette de la sortie et installez-la en utilisantPalettes -> Install Palette...

Si vous rencontrez des problèmes, postez un commentaire ici. Téléchargez la version notebook ici .


Begin["SOUploader`"];

Global`palette = PaletteNotebook@DynamicModule[{},

   Column[{
     Button["Upload to SE",
      With[{img = rasterizeSelection1[]},
       If[img === $Failed, Beep[], uploadWithPreview[img]]],
      Appearance -> "Palette"],

     If[$OperatingSystem === "Windows",

      Button["Upload to SE (pp)",
       With[{img = rasterizeSelection2[]},
        If[img === $Failed, Beep[], uploadWithPreview[img]]],
       Appearance -> "Palette"],

      Unevaluated@Sequence[]
      ]
     }],

   (* Init start *)
   Initialization :>
    (

     stackImage::httperr = "Server returned respose code: `1`";
     stackImage::err = "Server returner error: `1`";

     stackImage[g_] :=
      Module[
       {getVal, url, client, method, data, partSource, part, entity,
        code, response, error, result},

       getVal[res_, key_String] :=
        With[{k = "var " <> key <> " = "},
         StringTrim[

          First@StringCases[
            First@Select[res, StringMatchQ[#, k ~~ ___] &],
            k ~~ v___ ~~ ";" :> v],
          "'"]
         ];

       data = ExportString[g, "PNG"];

       JLink`JavaBlock[
        url = "http://stackoverflow.com/upload/image";
        client =
         JLink`JavaNew["org.apache.commons.httpclient.HttpClient"];
        method =
         JLink`JavaNew[
          "org.apache.commons.httpclient.methods.PostMethod", url];
        partSource =
         JLink`JavaNew[
          "org.apache.commons.httpclient.methods.multipart.\
ByteArrayPartSource", "mmagraphics.png",
          JLink`MakeJavaObject[data]@toCharArray[]];
        part =
         JLink`JavaNew[
          "org.apache.commons.httpclient.methods.multipart.FilePart",
          "name", partSource];
        part@setContentType["image/png"];
        entity =
         JLink`JavaNew[
          "org.apache.commons.httpclient.methods.multipart.\
MultipartRequestEntity", {part}, method@getParams[]];
        method@setRequestEntity[entity];
        code = client@executeMethod[method];
        response = method@getResponseBodyAsString[];
        ];

       If[code =!= 200, Message[stackImage::httperr, code];
        Return[$Failed]];
       response = StringTrim /@ StringSplit[response, "\n"];

       error = getVal[response, "error"];
       result = getVal[response, "result"];
       If[StringMatchQ[result, "http*"],
        result,
        Message[stackImage::err, error]; $Failed]
       ];

     stackMarkdown[g_] :=
      "![Mathematica graphics](" <> stackImage[g] <> ")";

     stackCopyMarkdown[g_] := Module[{nb, markdown},
       markdown = Check[stackMarkdown[g], $Failed];
       If[markdown =!= $Failed,
        nb = NotebookCreate[Visible -> False];
        NotebookWrite[nb, Cell[markdown, "Text"]];
        SelectionMove[nb, All, Notebook];
        FrontEndTokenExecute[nb, "Copy"];
        NotebookClose[nb];
        ]
       ];

     (* Returns available vertical screen space,
     taking into account screen elements like the taskbar and menu *)


     screenHeight[] := -Subtract @@
        Part[ScreenRectangle /. Options[$FrontEnd, ScreenRectangle],
         2];

     uploadWithPreview[img_Image] :=
      CreateDialog[
       Column[{
         Style["Upload image to the Stack Exchange network?", Bold],
         Pane[

          Image[img, Magnification -> 1], {Automatic,
           Min[screenHeight[] - 140, 1 + ImageDimensions[img][[2]]]},
          Scrollbars -> Automatic, AppearanceElements -> {},
          ImageMargins -> 0
          ],
         Item[
          ChoiceButtons[{"Upload and copy MarkDown"}, \
{stackCopyMarkdown[img]; DialogReturn[]}], Alignment -> Right]
         }],
       WindowTitle -> "Upload image to Stack Exchange?"
       ];

     (* Multiplatform, fixed-width version.
        The default max width is 650 to fit Stack Exchange *)
     rasterizeSelection1[maxWidth_: 650] :=
      Module[{target, selection, image},
       selection = NotebookRead[SelectedNotebook[]];
       If[MemberQ[Hold[{}, $Failed, NotebookRead[$Failed]], selection],

        $Failed, (* There was nothing selected *)

        target =
         CreateDocument[{}, WindowSelected -> False, Visible -> False,
           WindowSize -> maxWidth];
        NotebookWrite[target, selection];
        image = Rasterize[target, "Image"];
        NotebookClose[target];
        image
        ]
       ];

     (* Windows-only pixel perfect version *)
     rasterizeSelection2[] :=
      If[
       MemberQ[Hold[{}, $Failed, NotebookRead[$Failed]],
        NotebookRead[SelectedNotebook[]]],

       $Failed, (* There was nothing selected *)

       Module[{tag},
        FrontEndExecute[
         FrontEndToken[FrontEnd`SelectedNotebook[], "CopySpecial",
          "MGF"]];
        Catch[
         NotebookGet@ClipboardNotebook[] /.
          r_RasterBox :>
           Block[{},
            Throw[Image[First[r], "Byte", ColorSpace -> "RGB"], tag] /;
              True];
         $Failed,
         tag
         ]
        ]
       ];
     )
   (* Init end *)
   ]

End[];

4

Je suis sûr que beaucoup de gens ont rencontré la situation où ils exécutent certaines choses, réalisant que non seulement cela a bloqué le programme, mais qu'ils n'ont pas non plus sauvegardé pendant les 10 dernières minutes!

ÉDITER

Après avoir souffert de cela pendant un certain temps, j'ai découvert un jour que l' on pouvait créer une sauvegarde automatique à partir du code Mathematica . Je pense que l'utilisation d'une telle sauvegarde automatique m'a beaucoup aidé dans le passé, et j'ai toujours pensé que la possibilité elle-même était quelque chose que peu de gens savent qu'ils peuvent faire.

Le code original que j'ai utilisé est en bas. Grâce aux commentaires, j'ai découvert que c'était problématique, et qu'il est préférable de le faire d'une manière alternative, en utilisant ScheduledTask(qui ne fonctionnera que dans Mathematica 8).

Le code pour cela peut être trouvé dans cette réponse de Sjoerd C. de Vries (Puisque je ne suis pas sûr de pouvoir le copier ici, je le laisse sous forme de lien uniquement.)


La solution ci-dessous utilise Dynamic. Il sauvegardera le notebook toutes les 60 secondes, mais apparemment seulement si sa cellule est visible . Je le laisse ici uniquement pour des raisons d'achèvement. (et pour les utilisateurs de Mathematica 6 et 7)

/ÉDITER

Pour le résoudre, j'utilise ce code au début d'un cahier:

Dynamic[Refresh[NotebookSave[]; DateString[], UpdateInterval -> 60]]

Cela enregistrera votre travail toutes les 60 secondes.
Je le préfère NotebookAutoSave[]car il enregistre avant que l'entrée ne soit traitée, et parce que certains fichiers sont plus du texte que des entrées.

Je l'ai trouvé à l'origine ici: http://en.wikipedia.org/wiki/Talk:Mathematica#Criticisms

Notez qu'une fois cette ligne exécutée, l'enregistrement se fera même si vous fermez et rouvrez votre fichier (tant que la mise à jour dynamique est activée).

Aussi, comme il n'y a pas d'annulation dans Mathematica , veillez à ne pas supprimer tout votre contenu, car l'enregistrement le rendra irréversible (par mesure de précaution, je supprime ce code de chaque cahier terminé)


vous pouvez également l'enregistrer sous un nom différent (par exemple en ajoutant l'heure et la date actuelles à la fin du nom de fichier) et peut-être dans un répertoire spécifique ("Sauvegardes", par exemple). ce serait comme une forme primitive de gestion des versions.
acl

Vous pouvez faire quelque chose comme NotebookSave[SelectedNotebook[], "work-" <> IntegerString[i] <> ".nb"]; i++, mais je pense que tout type de référence au nom actuel du bloc-notes deviendra récursif.
tsvikas

2
Je pensais que les Dynamicobjets ne sont rafraîchis que lorsqu'ils sont visibles, donc je ne serais pas sûr que cette méthode fonctionnerait si, par exemple, vous faites défiler l' Dynamicobjet hors de la zone visible. Là encore, je n'ai pas essayé. En tout cas, je l'ai simplement proposé à titre de suggestion.
acl

1
Vous pouvez tester cela en utilisant Dynamic[Refresh[i++, UpdateInterval -> 1, TrackedSymbols -> {}]]. Faites défiler le nombre incrémentiel de vue, attendez une minute, faites défiler vers l'arrière et voyez que le nombre n'est pas incrémenté de 60. À propos UpdateInterval: ceci est généralement utilisé si possible, mais si votre code comprend des variables qui changent, ce changement déclenche une nouvelle actualisation avant le l'intervalle se termine. Essayez la ligne ci-dessus sansTrackedSymbols
Sjoerd C. de Vries

1
@ j0ker5 Essayez mon code ci-dessus et vous pouvez voir que UpdateInterval ne force pas toujours les mises à jour à être espacées avec l'intervalle spécifié. Ce code montre également que Dynamic ne fonctionne que si la cellule dans laquelle il est contenu est visible dans l'interface . Il s'arrête vraiment au moment où il est hors de vue. Les gens ne devraient vraiment pas faire confiance à ce code pour enregistrer leurs fichiers, car ce n'est pas le cas. Son dangereux
Sjoerd C. de Vries


3

Je trouve très utile lors du développement de packages d'ajouter ce raccourci clavier à mon SystemFiles/FrontEnd/TextResources/Windows/KeyEventTranslations.trfichier.

(* Evaluate Initialization Cells: Real useful for reloading library changes. *)

Item[KeyEvent["i", Modifiers -> {Control, Command}],
    FrontEndExecute[
        FrontEndToken[
            SelectedNotebook[],
            "EvaluateInitialization"]]],

Ensuite, pour chaque, Packagename.mje PackagenameTest.nbcrée un cahier de test et les 2 premières cellules du cahier de test sont définies comme cellules d'initialisation. Dans la première cellule j'ai mis

Needs["PackageManipulations`"]

pour charger la très utile bibliothèque PackageManipulations qui a été écrite par Leonid. La deuxième cellule contient

PackageRemove["Packagename`Private`"]
PackageRemove["Packagename`"]
PackageReload["Packagename`"]

qui font tous le rechargement du paquet. Notez que les deux premières lignes ne concernent que Removetous les symboles car j'aime garder les contextes aussi propres que possible.

Ensuite, le flux de travail pour écrire et tester un package devient quelque chose comme ça.

  1. Enregistrez les modifications dans Packagename.m.
  2. Allez PackagenameTest.nbet faites CTRL + ALT + i.

Cela provoque le rechargement du package par les cellules d'initialisation, ce qui simplifie grandement les tests.


1

La fonction suivante format[expr_]peut être utilisée pour indenter / formater des mathematicaexpressions non formatées qui s'étendent sur une page

indent[str_String, ob_String, cb_String, delim_String] := 
  Module[{ind, indent, f, tab}, ind = 0; tab = "    ";
   indent[i_, tab_, nl_] := nl <> Nest[tab <> ToString[#] &, "", i];
   f[c_] := (indent[ind, "", " "] <> c <> indent[++ind, tab, "\n"]) /;StringMatchQ[ob, ___ ~~ c ~~ ___];
   f[c_] := (indent[--ind, "", " "] <> c <> indent[ind, tab, "\n"]) /;StringMatchQ[cb, ___ ~~ c ~~ ___];
   f[c_] := (c <> indent[ind, tab, "\n"]) /;StringMatchQ[delim, ___ ~~ c ~~ ___];
   f[c_] := c;
   f /@ Characters@str // StringJoin];
format[expr_] := indent[expr // InputForm // ToString, "[({", "])}", ";"];

(*    
format[Hold@Module[{ind, indent, f, tab}, ind = 0; tab = "    ";
 indent[i_, tab_, nl_] := nl <> Nest[tab <> ToString[#] &, "", i];
 f[c_] := (indent[ind, "", " "] <> c <> indent[++ind, tab, "\n"]) /;StringMatchQ[ob, ___ ~~ c ~~ ___];
 f[c_] := (indent[--ind, "", " "] <> c <> indent[ind, tab, "\n"]) /;StringMatchQ[cb, ___ ~~ c ~~ ___];
 f[c_] := (c <> indent[ind, tab, "\n"]) /;StringMatchQ[delim, ___ ~~ c ~~ ___];
 f[c_] := c;
 f /@ Characters@str // StringJoin]]
*)

réf: /codegolf/3088/indent-a-string-using-given-parentheses


Pourquoi l'utilisez-vous dans la pratique? La sortie est un peu trop "drôle" pour être lisible soit lorsqu'elle est appliquée à votre code ou à des données (listes, format@RandomInteger[10,{3,3}]): pastebin.com/nUT54Emq Puisque vous avez déjà les bases et que cela vous intéresse, pouvez-vous améliorer le code pour produire un formatage lisible? Ensuite, la prochaine étape serait de créer un bouton Coller qui créera une cellule d'entrée avec du code Mathematica bien indenté (en préservant de préférence les commentaires !!) Voir aussi ma question connexe .
Szabolcs
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.