¿Qué hay en su bolsa de herramientas de Mathematica? [cerrado]


152

Todos sabemos que Mathematica es excelente, pero a menudo también carece de una funcionalidad crítica. ¿Qué tipo de paquetes / herramientas / recursos externos utiliza con Mathematica?

Editaré (e invitaré a cualquier otra persona que lo haga también) esta publicación principal para incluir recursos que se centren en la aplicabilidad general en la investigación científica y que la mayor cantidad de personas posible encuentren útil. Siéntase libre de contribuir con cualquier cosa, incluso pequeños fragmentos de código (como hice a continuación para una rutina de sincronización).

Además, las características indocumentadas y útiles en Mathematica 7 y más allá de lo que se encontró, o desenterrado de algún documento / sitio son bienvenidas.

Incluya una breve descripción o comentario sobre por qué algo es genial o qué utilidad proporciona. Si enlaza a libros en Amazon con enlaces de afiliados, por favor mencione, por ejemplo, poniendo su nombre después del enlace.


Paquetes:

  1. LevelSchemees un paquete que expande enormemente la capacidad de Mathematica para producir trazados atractivos. Lo uso si no para otra cosa que para el control mucho, mucho mejor sobre las marcas de cuadros / ejes. Su versión más reciente se llama SciDraw, y se lanzará en algún momento de este año.
  2. David Park's Presentation Package(US $ 50 - sin cargo por actualizaciones)
  3. El grassmannOpspaquete de Jeremy Michelson proporciona recursos para hacer álgebra y cálculo con variables y operadores de Grassmann que tienen relaciones de conmutación no triviales.
  4. GrassmannAlgebraPaquete y libro de John Brown para trabajar con álgebras de Grassmann y Clifford.
  5. El RISC (Instituto de Investigación para la Computación Simbólica) tiene una variedad de paquetes para Mathematica (y otros idiomas) disponibles para descargar. En particular, existe el Teorema para la demostración automatizada de teoremas, y la multitud de paquetes para suma simbólica, ecuaciones de diferencia, etc. en la página de software del grupo Algorithmic Combinatorics .

Herramientas:

  1. MASHes el excelente script de Perl de Daniel Reeves que esencialmente proporciona soporte de scripts para Mathematica v7. (Ahora integrado a partir de Mathematica 8 con la -scriptopción).
  2. Un alternate Mathematica shellcon una entrada de línea de lectura GNU (usando python, * nix solamente)
  3. El paquete ColourMaths le permite seleccionar visualmente partes de una expresión y manipularlas. http://www.dbaileyconsultancy.co.uk/colour_maths/colour_maths.html

Recursos:

  1. El propio repositorio de Wolfram MathSourcetiene muchos útiles aunque portátiles estrechos para diversas aplicaciones. Consulte también las otras secciones, como

  2. El Mathematica Wikibook .

Libros:

  1. Programación de Mathematica: una introducción avanzada de Leonid Shifrin ( web, pdf) es una lectura obligada si desea hacer algo más que bucles For en Mathematica. Tenemos el placer de tener que Leonidresponder preguntas aquí.
  2. Métodos cuánticos con Mathematica por James F. Feagin ( amazon )
  3. El libro de Mathematica de Stephen Wolfram ( amazon ) ( web)
  4. Esquema de Schaum ( amazon )
  5. Mathematica en acción por Stan Wagon ( Amazon ) - 600 páginas de ejemplos claros y sube a la versión 7. de Mathematica. Las técnicas de visualización son especialmente buenas, puede ver algunas de ellas en el autor Demonstrations Page.
  6. Fundamentos de programación de Mathematica por Richard Gaylord ( pdf) - Una buena introducción concisa a la mayoría de lo que necesita saber sobre la programación de Mathematica.
  7. Mathematica Cookbook por Sal Mangano publicado por O'Reilly 2010 832 páginas. - Escrito en el conocido estilo O'Reilly Cookbook: Problema - Solución. Para intermedios.
  8. Ecuaciones diferenciales con Mathematica, 3ra ed. Elsevier 2004 Amsterdam por Martha L. Abell, James P. Braselton - 893 páginas Para principiantes, aprenda a resolver DE y Mathematica al mismo tiempo.

Características no documentadas (o apenas documentadas):

  1. Cómo personalizar los atajos de teclado de Mathematica. Ver this question.
  2. Cómo inspeccionar patrones y funciones utilizadas por las propias funciones de Mathematica. Verthis answer
  3. ¿Cómo lograr un tamaño consistente para GraphPlots en Mathematica? Ver this question.
  4. Cómo producir documentos y presentaciones con Mathematica. Ver this question.

2
Mathematica 8 está disponible con una integración de script de shell mucho mejor. wolfram.com/mathematica/new-in-8/mathematica-shell-scripts
Joshua Martell el

2
+1, para LevelScheme. Es un poco lento, a veces. Pero tiene un método sensato para crear marcas de graduación, y es mucho más fácil crear diseños dignos de diario para gráficos Grid, o algo similar.
rcollyer

2
Según lo propuesto por Alexey en los comentarios sobre esta pregunta stackoverflow.com/questions/5152551/… , propuse el cambio de nombre de la etiqueta para Mathematica aquí: meta.stackexchange.com/questions/81152/… . Echa un vistazo y vota si estás de acuerdo. Lo publico aquí porque esta pregunta tiene muchos favoritos en la comunidad Mma aquí.
Dr. belisario

1
En general, esta pregunta realmente debería ser wiki comunitaria por todas las razones habituales: no tiene una respuesta correcta y es más una lista que cualquier otra cosa. Pido disculpas a todos los que se han beneficiado generosamente de la reputación de esta pregunta.
rcollyer

2
Estas respuestas a esta pregunta son constructivas, debe reabrirse.
MR

Respuestas:


29

He mencionado esto antes, pero la herramienta que encuentro más útil es una aplicación Reapy Sowque imita / extiende el comportamiento de GatherBy:

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

Esto me permite agrupar listas por cualquier criterio y transformarlas en el proceso. La forma en que funciona es que una función de criterio ( f) etiqueta cada elemento de la lista, cada elemento es transformado por una segunda función suministrada ( g), y la salida específica es controlada por una tercera función ( h). La función hacepta dos argumentos: una etiqueta y una lista de los elementos recopilados que tienen esa etiqueta. Los elementos conservan su orden original, por lo que si configura h = #1&, obtendrá un no ordenado Union, como en los ejemplos de Reap. Pero, se puede usar para procesamiento secundario.

Como ejemplo de su utilidad, he estado trabajando con Wannier90 que genera el Hamiltoniano espacialmente dependiente en un archivo donde cada línea es un elemento diferente en la matriz, de la siguiente manera

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

Para convertir esa lista en un conjunto de matrices, reuní todas las sublistas que contienen la misma coordenada, convertí la información del elemento en una regla (es decir, {i, j} -> Re [Hij] + I Im [Hij]), y luego convirtió las reglas recopiladas en un SparseArraytodo con un solo revestimiento:

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

Honestamente, esta es mi navaja suiza, y hace que las cosas complejas sean muy simples. La mayoría de mis otras herramientas son algo específicas del dominio, por lo que probablemente no las publique. Sin embargo, la mayoría, si no todos, de ellos hacen referencia SelectEquivalents.

Editar : no imita por completo, ya GatherByque no puede agrupar múltiples niveles de la expresión de la manera más simple GatherByposible. Sin embargo, Mapfunciona bien para la mayoría de lo que necesito.

Ejemplo : @Yaroslav Bulatov ha pedido un ejemplo autónomo. Aquí hay uno de mi investigación que se ha simplificado enormemente. Entonces, digamos que tenemos un conjunto de puntos en un plano

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}}

y nos gustaría reducir el número de puntos mediante un conjunto de operaciones de simetría. (Para los curiosos, estamos generando el pequeño grupo de cada punto.) Para este ejemplo, usemos un eje de rotación de cuatro pliegues alrededor del eje z

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

Usando SelectEquivalentspodemos agrupar los puntos que producen el mismo conjunto de imágenes bajo estas operaciones, es decir, son equivalentes, usando lo siguiente

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}}}

que produce 3 sublistas que contienen los puntos equivalentes. (Tenga en cuenta que Unionaquí es absolutamente vital, ya que garantiza que cada punto produzca la misma imagen. Originalmente, lo usé Sort, pero si un punto se encuentra en un eje de simetría, es invariante bajo la rotación alrededor de ese eje dando una imagen adicional de sí mismo Entonces, Unionelimina estas imágenes adicionales. Además, GatherByproduciría el mismo resultado.) En este caso, los puntos ya están en una forma que usaré, pero solo necesito un punto representativo de cada grupo y me gustaría contar de los puntos equivalentes. Como no necesito transformar cada punto, uso elIdentityfuncionar en la segunda posición. Para la tercera función, debemos tener cuidado. El primer argumento que se le pasará serán las imágenes de los puntos bajo las rotaciones, que para el punto {0,0,0}es una lista de cuatro elementos idénticos, y usarlo arrojaría la cuenta. Sin embargo, el segundo argumento es solo una lista de todos los elementos que tienen esa etiqueta, por lo que solo contendrá {0,0,0}. En codigo,

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}}

Tenga en cuenta que este último paso se puede lograr con la misma facilidad

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

Pero, es fácil con esto y el ejemplo menos completo anterior para ver cómo son posibles transformaciones muy complejas con un mínimo de código.


El código Fortran77 original fue reestructurado el Día de Acción de Gracias de 1996, y por lo tanto durante muchos años conocido como turkey.f ...: D Muy buenos gráficos BTW. Me recordó el monstruo de Falicov ...
Dr. belisario

@belisarius, no había leído la historia, eso es gracioso. Acabo de comenzar a usar Wannier90, pero es uno de los Fortrancódigos mejor organizados y bien escritos que he visto. Casi me hace considerar usar Fortran...
rcollyer

Me pregunto si podría agregar un ejemplo autónomo de SelectEquivalents en acción
Yaroslav Bulatov el

@Yaroslav Bulatov, agregó un ejemplo, por solicitud. Déjeme saber si esto ayuda. Si no es así, veremos qué podemos hacer.
rcollyer

Obtiene la marca de verificación de esta "pregunta" para la contribución del fragmento de código más interesante.
Timo

57

Una de las cosas buenas de la interfaz del cuaderno de Mathematica es que puede evaluar expresiones en cualquier idioma, no solo en Mathematica. Como un ejemplo simple, considere crear un nuevo tipo de celda de entrada de Shell que pase la expresión contenida al shell del sistema operativo para su evaluación.

Primero, defina una función que delegue la evaluación de un comando textual al shell externo:

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

El segundo argumento es necesario e ignorado por razones que se harán evidentes más adelante. A continuación, queremos crear un nuevo estilo llamado Shell :

  1. Abre un cuaderno nuevo.
  2. Seleccione el elemento de menú Formato / Editar hoja de estilo ...
  3. En el cuadro de diálogo, junto a Ingrese un nombre de estilo: tipo Shell.
  4. Seleccione el soporte de celda al lado del nuevo estilo.
  5. Seleccione el elemento de menú Celda / Mostrar expresión
  6. Sobrescriba la expresión de la celda con el Texto del Paso 6 que figura a continuación.
  7. Una vez más, seleccione el elemento de menú Celda / Mostrar expresión
  8. Cierra el diálogo.

Use la siguiente expresión de celda como Texto del Paso 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 mayor parte de esta expresión se copió directamente del estilo del programa incorporado . Los cambios clave son estas líneas:

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

Evaluatablehabilita la funcionalidad MAYÚS + ENTRAR para la celda. La evaluación llamará al CellEvaluationFunctionpasar el contenido de la celda y el tipo de contenido como argumentos ( shellEvaluateignora el último argumento). CellFrameLabelses solo un detalle que permite al usuario identificar que esta celda es inusual.

Con todo esto en su lugar, ahora podemos ingresar y evaluar una expresión de shell:

  1. En el cuaderno creado en los pasos anteriores, cree una celda vacía y seleccione el soporte de celda.
  2. Seleccione el elemento de menú Formato / Estilo / Shell .
  3. Escriba un comando de shell del sistema operativo válido en la celda (por ejemplo, 'ls' en Unix o 'dir' en Windows).
  4. Presione MAYÚS + ENTRAR.

Es mejor mantener este estilo definido en una hoja de estilo ubicada centralmente. Además, las funciones de evaluación como shellEvaluatese definen mejor como apéndices utilizando DeclarePackage en init.m. Los detalles de ambas actividades están más allá del alcance de esta respuesta.

Con esta funcionalidad, se pueden crear cuadernos que contienen expresiones de entrada en cualquier sintaxis de interés. La función de evaluación puede escribirse en puro Mathematica, o delegar cualquiera o todas las partes de la evaluación a una agencia externa. Tenga en cuenta que hay otros ganchos que se relacionan con la evaluación celular, como CellEpilog, CellPrology CellDynamicExpression.

Un patrón común implica escribir el texto de expresión de entrada en un archivo temporal, compilar el archivo en algún idioma, ejecutar el programa y capturar la salida para su visualización final en la celda de salida. Hay muchos detalles que abordar cuando se implementa una solución completa de este tipo (como capturar mensajes de error correctamente), pero uno debe apreciar el hecho de que no solo es posible hacer cosas como esta, sino también prácticas.

En una nota personal, son características como esta las que hacen que la interfaz del portátil sea el centro de mi universo de programación.

Actualizar

La siguiente función auxiliar es útil para crear tales celdas:

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

Se usa así:

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

Ahora, si shellCell[]se evalúa, la celda de entrada se eliminará y se reemplazará con una nueva celda de entrada que evalúa su contenido como un comando de shell.


3
@WReach +100! ¡Ojalá supiera esto antes! Esto es algo muy útil, al menos para mí. ¡Gracias por compartir!
Leonid Shifrin

¡Esto se ve muy elegante! CellEvaluationFunctionCreo que también podría usarse para piratear sintaxis de bajo nivel.
Mr.Wizard

@Leonid Al menos para FrontEnd, ¿es CellEvaluationFunctionel gancho que estabas buscando?
Mr.Wizard

2
Además: hay otra Cellopción que se relaciona con la evaluación de células - Evaluator -> "EvaluatorName". El significado de "EvaluatorName"podría configurarse a través del cuadro de diálogo Evaluación :: Opciones de configuración del núcleo ... Todavía no sé si es posible configurarlo mediante programación ... Esta técnica permite utilizar diferentes MathKernels en diferentes Cells en un cuaderno. Estos MathKernels pueden ser de diferentes versiones de Mathematica instaladas.
Alexey Popkov

1
@Szabolcs Todos mis propios usos de esta técnica implican un enfoque stdin _ / _ stdout como se ilustra arriba, o una solicitud remota autónoma como una consulta SQL o una operación HTTP. Puede intentar configurar una aplicación web Python REPL (como esta ) e interactuar con ella usando Import, o tal vez iniciar un proceso externo de Python y comunicarse a través de sus flujos (por ejemplo, usando un Java ProcessBuilder ). Estoy seguro de que hay una mejor manera de Mathematica - suena como una buena pregunta SO :)
WReach

36

Todd Gayley (Wolfram Research) acaba de enviarme un buen truco que permite "ajustar" las funciones integradas con código arbitrario. Siento que tengo que compartir este útil instrumento. La siguiente es la respuesta de Todd en mi question.

Un poco de historia interesante (?): Ese estilo de pirateo para "envolver" una función incorporada fue inventado alrededor de 1994 por Robby Villegas y yo, irónicamente para la función Mensaje, en un paquete llamado ErrorHelp que escribí para Mathematica Journal en aquel momento. Ha sido usado muchas veces, por muchas personas, desde entonces. Es un poco un truco interno, pero creo que es justo decir que se ha convertido en la forma canónica de inyectar su propio código en la definición de una función incorporada. Hace el trabajo bien. Por supuesto, puede colocar la variable $ inMsg en cualquier contexto privado que desee.

Unprotect[Message];

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

Protect[Message];

@Alexey Tengo dificultades para entender esto. ¿Podría explicar cómo funciona esto? ¿No debería haber un [mensaje] desprotegido en alguna parte? ¿Y este ejemplo no contiene recursión infinita? Y! TrueQ [$ inMsg] ¿eso tiene sentido con $ inMsg definido dentro del alcance del Bloque e indefinido fuera del Bloque?
Sjoerd C. de Vries

9
@Sjoerd Por lo que entiendo, la Unprotectverdad tiene que ser, simplemente se dejó de lado. El punto de Block(alcance dinámico) y $inMsges exactamente para evitar la recursión infinita. Debido a $inMsgque no está definido en el exterior (este es un requisito importante), al principio, se TrueQevalúa Falsee ingresamos al cuerpo de la función. Pero cuando tenemos la llamada a la función dentro del cuerpo, la condición se evalúa como False(ya que la variable ha sido redefinida por Block). Por lo tanto, la regla definida por el usuario no coincide, y en su lugar se usa la regla incorporada.
Leonid Shifrin

1
@Leonid Gracias, lo entiendo ahora. ¡Muy inteligente!
Sjoerd C. de Vries

1
Acabo de descubrir que esta técnica fue discutida por Robby Villegas de Wolfram Research en la Conferencia de Desarrolladores de 1999. Consulte el cuaderno "Trabajar con expresiones sin evaluar" publicado aquí . En este cuaderno, Robby Villegas analiza este truco en la subsección "Mi truco de bloqueo para atrapar llamadas a funciones integradas".
Alexey Popkov

1
@ Mr.Wizard Esta no es la única forma de hacer esto. Durante mucho tiempo, utilicé una versión en la que redefine el DownValuestiempo de ejecución, puede ver esta publicación groups.google.com/group/comp.soft-sys.math.mathematica/… , por ejemplo ( SetDelayedredefinición) . Pero mi método es menos elegante, menos robusto, más propenso a errores y hace que la interrupción de la recursión sea mucho menos trivial de implementar. Entonces, en la mayoría de las situaciones, el método descrito por @Alexey gana sin dudas.
Leonid Shifrin

25

Este no es un recurso completo, por lo que lo incluyo aquí en la sección de respuestas, pero lo he encontrado muy útil al resolver problemas de velocidad (que, desafortunadamente, es una gran parte de lo que trata la programación de 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};

El uso es entonces simplemente timeAvg@funcYouWantToTest.

EDIT: Sr. Asistente ha proporcionado una versión más simple que elimina Throwy Catchy es un poco más fácil de analizar:

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

EDITAR: Aquí hay una versión de acl (tomada de aquí ):

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]

Hecho de nuevo y otra vez ... es hora de entrar en mi propia bolsa. tnx!
Dr. belisarius

1
Un problema con este código (bueno, puede ser que este sea el punto de vista de un perfeccionista) es que podemos atrapar algo que no lanzamos e interpretarlo como un resultado de tiempo incorrecto. Ambos Catchy Throwdeberían haber sido utilizados con etiquetas de excepción únicas.
Leonid Shifrin

2
Timo, me alegra que te guste mi interpretación lo suficiente como para incluirla. Gracias por darme crédito también. Tengo curiosidad por la forma en que formateaste mi código. No sigo ninguna directriz particular en mi propio código, aparte de facilitarme la lectura; ¿Hay una escuela de pensamiento detrás de su reformateo, o es solo preferencia? Mathematica no fomenta el formateo preciso del código debido a la forma en que refluye la entrada, pero publicar código aquí me está haciendo comenzar a pensar en ello. Por cierto, creo que te refieres a " Throwy Catch" en lugar de " Reapy Sow".
Mr.Wizard

1
@ Simon, Mr.Wizard, uso este método para cronometrar diferentes versiones de funciones pequeñas que se llamarán muchas veces. No necesariamente en una estructura de bucle, pero ciertamente dentro de construcciones que MMA optimiza. En este contexto, la ejecución de un bucle tiene sentido y el rendimiento estará cerca de la aplicación de la vida real. Para sincronizar funciones complejas grandes (tal vez incluso celdas de inicialización completas), el método de Simon dará un mejor resultado. En general, estoy más interesado en los valores relativos y cualquiera de los métodos debería funcionar allí.
Timo

3
Ahora hay RepeatedTimingque hacer esto.
masterxilo

20

Internal`InheritedBlock

Recientemente he aprendido la existencia de funciones tan útiles como las Internal`InheritedBlockde este mensaje de Daniel Lichtblau en el grupo de noticias oficial.

Según tengo entendido, Internal`InheritedBlockpermite pasar una copia de una función saliente dentro del Blockalcance:

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]

¡Creo que esta función puede ser muy útil para todos los que necesiten modificar temporalmente las funciones integradas!

Comparación con el bloque

Definamos alguna función:

a := Print[b]

Ahora deseamos pasar una copia de esta función al Blockámbito. El juicio ingenuo no da lo que queremos:

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

During evaluation of In[9]:= b

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

Ahora tratando de usar la definición retrasada en el primer argumento de Block(también es una característica no documentada):

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

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

During evaluation of In[3]:= b

Vemos que en este caso afunciona, pero no tenemos una copia del original adentro del Blockalcance.

Ahora intentemos Internal`InheritedBlock:

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

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

¡Tenemos una copia de la definición original adentro del Blockalcance y podemos modificarla de la manera que queramos sin afectar la definición global de a!


+1 Muy útil! Una herramienta más en la bolsa y 10 puntos más cerca del privilegio Editar para usted.
Mr.Wizard

Para mí, esto aparece como una variante de evaluación temprana o tardía o nula y completa.
user2432923

19

Mathematica es una herramienta aguda, pero puede cortarlo con su comportamiento algo sin tipo y avalanchas de mensajes de diagnóstico crípticos . Una forma de lidiar con esto es definir funciones siguiendo este modismo:

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

Eso es un montón de repeticiones, que con frecuencia me siento tentado a omitir. Especialmente cuando se realizan prototipos, lo que sucede mucho en Mathematica. Entonces, uso una macro llamadadefine que me permite permanecer disciplinado, con mucho menos repetitivo.

Un uso básico de definees así:

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

fact[5]

120

Al principio no parece mucho, pero hay algunos beneficios ocultos. El primer servicio quedefine proporciona es que se aplica automáticamente ClearAllal símbolo que se está definiendo. Esto asegura que no haya definiciones sobrantes, una ocurrencia común durante el desarrollo inicial de una función.

El segundo servicio es que la función que se define se "cierra" automáticamente. Con esto quiero decir que la función emitirá un mensaje y abortará si se invoca con una lista de argumentos que no coincide con una de las definiciones:

fact[-1]

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

Este es el valor principal de define , que detecta una clase de error muy común.

Otra conveniencia es una forma concisa de especificar atributos en la función que se está definiendo. Hagamos la función Listable:

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

fact[{3, 5, 8}]

{6, 120, 40320}

Además de todos los atributos normales, defineacepta un atributo adicional llamado Open. Esto evita defineagregar la definición de error general a la función:

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

successor /@ {1, "hi"}

{2, successor["hi"]}

Se pueden definir múltiples atributos para una función:

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

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

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

Sin más preámbulos, aquí está la definición 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: ``";

La implementación exhibida no admite valores ascendentes ni currificación, ni patrones más generales que la definición de función simple. Sigue siendo útil, sin embargo.


2
+1: esto es algo realmente útil. He estado usando herramientas similares. Las macros (así como la introspección y otras técnicas de metaprogramación) pueden ser muy poderosas, pero en general parecen ser poco apreciadas dentro de la comunidad de Mathematica, o al menos esta ha sido mi impresión hasta ahora.
Leonid Shifrin el

Acabo de definir algo similar. +1 para el soporte de CompoundExpression para hacer múltiples definiciones, Abortar [] (parece mejor que aún más mensajes) y Abrir (agradable para, por ejemplo, constructores).
masterxilo

16

Comience sin un cuaderno en blanco abierto

Me molestó que Mathematica comenzara con un cuaderno en blanco abierto. Podría cerrar este cuaderno con un script, pero aún así se abriría brevemente. Mi truco es crear un archivo que Invisible.nbcontenga:

Notebook[{},Visible->False]

Y agregue esto a mi Kernel\init.m:

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

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

Ahora empiezo Mathematica abriendo Invisible.nb

Puede haber una mejor manera, pero esto me ha servido bien.


Personalizado FoldyFoldList

Fold[f, x] se hace equivalente a Fold[f, First@x, Rest@x]

Por cierto, creo que esto puede llegar a una versión futura de Mathematica.

¡Sorpresa! Esto se ha implementado, aunque actualmente no está documentado. Me informan que fue implementado en 2011 por Oliver Ruebenkoenig, aparentemente poco después de que publiqué esto. Gracias 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]

Actualizado para permitir esto:

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

"Partición dinámica"

Ver Mathematica.SE post # 7512 para una nueva versión de esta función.

Con frecuencia quiero particionar una lista de acuerdo con una secuencia de longitudes.

ejemplo de pseudocódigo:

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

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

Se me ocurrió esto:

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

Lo que luego completé con esto, incluida la prueba de argumentos:

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

El tercer argumento controla lo que sucede con los elementos más allá de la especificación dividida.


Los trucos de Mathematica de Szabolcs

El que uso con más frecuencia es la paleta de datos tabulares pegar

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"]]]]]}

Modificar datos externos desde dentro Compile

Recientemente, Daniel Lichtblau mostró este método que nunca había visto antes. En mi opinión, extiende significativamente la utilidad 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 ¡Una buena colección! Con respecto a las modificaciones externas desde adentro Compile, toda mi publicación aquí: stackoverflow.com/questions/5246330/… , debía mostrar esta posibilidad en un entorno no trivial (ya había una solución más rápida y más corta al problema en cuestión) . En mi opinión, la mayor victoria aquí es la capacidad de emular el paso por referencia y dividir grandes funciones compiladas en fragmentos más manejables y reutilizables.
Leonid Shifrin

1
También puede ajustar la información de sintaxis del rebaño y FoldList en su nueva definición: SyntaxInformation [Plegado] = { "ArgumentsPattern" -> {_, . , _}}; SyntaxInformation [FoldList] = {"ArgumentsPattern" -> {_, _., {_ }}};
faysou

14

Problemas y soluciones generales de exportación de PDF / EMF

1) Es completamente inesperado e indocumentado, pero Mathematica exporta y guarda gráficos en formatos PDF y EPS usando un conjunto de definiciones de estilo que difiere del que se usa para mostrar los Cuadernos en la pantalla. De manera predeterminada, las computadoras portátiles se muestran en la pantalla en el entorno de estilo "Trabajo" (que es el valor predeterminado para la opción ScreenStyleEvironmentglobal $FrontEnd) pero se imprimen en el "Printout"entorno de estilo (que es el valor predeterminado para la opción PrintingStyleEnvironmentglobal $FrontEnd). Cuando uno exporta gráficos en formatos ráster como GIF y PNG o en formato EMF, Mathematica genera gráficos que se ven exactamente como se ven dentro de Notebook. Parece que el"Working"El entorno de estilo se utiliza para renderizar en este caso. ¡Pero no es el caso cuando exporta / guarda algo en formato PDF o EPS! En este caso,"Printout" entorno de estilo se usa por defecto yque difiere muy profundamente del entorno de estilo "de trabajo". En primer lugar, el "Printout"entorno de estilo se establece Magnificationen el 80% . En segundo lugar, utiliza sus propios valores para los tamaños de fuente de diferentes estilos y esto da como resultado cambios de tamaño de fuente inconsistentes en el archivo PDF genacional en comparación con la representación original en pantalla. Este último puede llamarse fluctuaciones de FontSize que son muy molestas. Pero, felizmente, esto se puede evitar configurando la opción PrintingStyleEnvironmentglobal $FrontEnd"Trabajar" :

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

2) El problema común al exportar a formato EMF es que la mayoría de los programas (no solo Mathematica ) generan un archivo que se ve bien en el tamaño predeterminado pero se vuelve feo cuando lo amplías. Es porque los metarchivos se muestrean con la fidelidad de resolución de pantalla . La calidad del archivo EMF generado se puede mejorar Magnifyincorporando el objeto gráfico original para que la exactitud del muestreo de los gráficos originales sea mucho más precisa. Compare dos archivos:

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 inserta estos archivos en Microsoft Word y los acerca, verá que la primera "a" tiene un diente de sierra y la segunda no (probado con Mathematica 6).

Chris DegnenImageResolution sugirió otra forma de hacerlo (esta opción tiene efecto al menos a partir de Mathematica 8):

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

3) En Mathematica tenemos tres formas de convertir gráficos en metarchivos: a través Exportde "EMF"(forma muy recomendada: produce metarchivos con la mayor calidad posible), a través del Save selection As...elemento del menú ( produce una figura mucho menos precisa , no se recomienda) y a través del Edit ► Copy As ► Metafileelemento del menú ( lo recomiendo en contra de esta ruta ).


13

Por demanda popular, el código para generar la trama de los 10 principales respondedores de SO (excepto las anotaciones ) utilizando la API de SO .

ingrese la descripción de la imagen aquí

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 publicó una pregunta pidiendo casi este código exacto. Tal vez sea más apropiado allí, con un ajuste o dos para adaptarse a la pregunta. Realmente valdría la pena la repetición, a diferencia de esta pregunta.
rcollyer

@rcollyer tiene razón. Esto es "Wiki de la comunidad"
Dr. belisarius

@belisarius Lo acabo de copiar en la respuesta a la pregunta de Brett ...
Sjoerd C. de Vries

@Sjoerd Su trama aquí no se actualiza automáticamente.
Dr. belisario

@belisarius En realidad, esperaba que tomaras esa tarea sobre ti ... ;-)
Sjoerd C. de Vries

13

Expresiones de almacenamiento en caché

Encuentro estas funciones muy útiles para almacenar en caché cualquier expresión. Lo interesante aquí para estas dos funciones es que la expresión retenida en sí misma se usa como una clave de la tabla hash / símbolo Cache o CacheIndex, en comparación con la conocida memorización en matemática donde solo se puede almacenar en caché el resultado si la función se define como f [x_]: = f [x] = ... Para que pueda almacenar en caché cualquier parte de un código, esto es útil si se llama a una función varias veces, pero solo algunas partes del código no se deben volver a calcular.

Para almacenar en caché una expresión independientemente de sus argumentos.

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

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

La segunda vez, la expresión devuelve 6 sin esperar.

Para almacenar en caché una expresión usando una expresión de alias que puede depender de un argumento de la expresión en caché.

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

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

Si expr tarda un poco en calcular, es mucho más rápido evaluar {"f", 2}, por ejemplo, para recuperar el resultado almacenado en caché.

Para una variación de estas funciones con el fin de tener una memoria caché localizada (es decir, la memoria caché se libera automáticamente fuera de la construcción del bloque), vea esta publicación Evite llamadas repetidas a la interpolación

Eliminar valores en caché

Para eliminar valores almacenados en caché cuando no conoce el número de definiciones de una función. Considero que las definiciones tienen un espacio en blanco en algún lugar de sus argumentos.

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

Para eliminar los valores en caché cuando conoce el número de definiciones de una función (va un poco más rápido).

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

Esto utiliza el hecho de que las definiciones de una función se encuentran al final de su lista de DownValues, los valores almacenados en caché están antes.

Usar símbolos para almacenar datos y funciones similares a objetos

También aquí hay funciones interesantes para usar símbolos como objetos.

Ya es bien sabido que puede almacenar datos en símbolos y acceder rápidamente a ellos utilizando DownValues

mysymbol["property"]=2;

Puede acceder a la lista de teclas (o propiedades) de un símbolo utilizando estas funciones en función de lo que envió en una publicación en este sitio:

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

Utilizo mucho esta función para mostrar todas las informaciones contenidas en los valores de un símbolo:

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

Finalmente, aquí hay una manera simple de crear un símbolo que se comporte como un objeto en la programación orientada a objetos (solo reproduce el comportamiento más básico de OOP pero la sintaxis me parece elegante):

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

Las propiedades se almacenan como DownValues ​​y los métodos como Upvalues ​​retrasados ​​en el símbolo creado por el Módulo que se devuelve. Encontré la sintaxis para function2 que es la sintaxis OO habitual para funciones en la estructura de datos de árbol en Mathematica .

Para obtener una lista de los tipos de valores existentes que tiene cada símbolo, consulte http://reference.wolfram.com/mathematica/tutorial/PatternsAndTransformationRules.html y http://www.verbeia.com/mathematica/tips/HTMLLinks/Tricks_Misc_4.html .

Por ejemplo prueba esto

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

Puede ir más allá si desea emular la herencia de objetos utilizando un paquete llamado InheritRules disponible aquí http://library.wolfram.com/infocenter/MathSource/671/

También puede almacenar la definición de la función no en newObject sino en un símbolo de tipo, por lo que si NewObject devuelve el tipo [newObject] en lugar de newObject, podría definir la función y function2 de esta manera fuera de NewObject (y no dentro) y tener el mismo uso que antes .

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

Use UpValues ​​[type] para ver que function y function2 están definidas en el símbolo de tipo.

Aquí se presentan más ideas sobre esta última sintaxis https://mathematica.stackexchange.com/a/999/66 .

Versión mejorada de SelectEquivalents

@rcollyer: Muchas gracias por traer SelectEquivalents a la superficie, es una función increíble. Aquí hay una versión mejorada de SelectEquivalents enumerados anteriormente con más posibilidades y el uso de opciones, esto hace que sea más fácil de usar.

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

Aquí hay ejemplos de cómo se puede usar esta versión:

Usando Mathematica Gather / Collect correctamente

¿Cómo haría una función de tabla dinámica en Mathematica?

Algoritmo de binning 2D rápido de Mathematica

Bolsa interna

Daniel Lichtblau describe aquí una interesante estructura interna de datos para listas crecientes.

Implementando un Quadtree en Mathematica

Funciones de depuración

Estas dos publicaciones apuntan a funciones útiles para la depuración:

¿Cómo depurar al escribir códigos pequeños o grandes usando Mathematica? banco de trabajo? depurador de mma? ¿o algo mas? (Enséñalo)

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

Aquí hay otra función basada en Reap and Sow para extraer expresiones de diferentes partes de un programa y almacenarlas en un símbolo.

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

Aquí hay un ejemplo

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*)

Otros recursos

Aquí hay una lista de enlaces interesantes para aprender:

Una colección de recursos de aprendizaje de Mathematica

Actualizado aquí: https://mathematica.stackexchange.com/a/259/66


Relacionado: " La mejor manera de construir una función con memoria ". WReach ha dado un sorprendente ejemplo de función simple que no solo recuerda sus valores, sino que también los escribe en un archivo y los lee hacia atrás al reiniciar.
Alexey Popkov

1
Relacionado: " Mathematica: Cómo borrar la memoria caché para un símbolo, es decir, valores de inercia sin patrón sin establecer ". Esta pregunta muestra cómo borrar el caché usando la f[x_] := f[x] = some codememorización estándar .
Simon

77
1 Hay un bonito conveniencia de notación que elimina la necesidad de repetir el lado izquierdo de la definición de una función de almacenamiento en caché, por ejemplo: c:Cache[expr_] := c = expr.
WReach

Bonita variante de SelectEquivalents. Sin embargo, creo que seguiría TagOnElementsiendo el segundo parámetro predeterminado, Identityya que es el más utilizado. Tampoco creo que lo haya incluido FinalOp, ya que se puede manejar dentro OpOnTaggedElems. También acortaría los nombres de las opciones, ya que su longitud hace que sea difícil escribir. Intenta TagFunction, TransformElement, TransformResults, y TagPatternen su lugar. Ambos, TagPatterny MapLevelson excelentes adiciones a la funcionalidad, y una buena reescritura, en general.
rcollyer

Gracias por tu comentario rcollyer. Lo tomé en cuenta y mejoré también la legibilidad del código. Mantengo FinalFunction porque funciona en el resultado de Reap, por ejemplo, si desea ordenar el resultado final por etiquetas si las mantiene.
faysou

12

Mis funciones de utilidad (tengo estas integradas en MASH, que se menciona en la pregunta):

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

Un truco que he usado, que le permite emular la forma en que la mayoría de las funciones integradas funcionan con argumentos malos (enviando un mensaje y luego devolviendo todo el formulario sin evaluar) explota una peculiaridad de la forma en que Conditionfunciona cuando se usa en una definición. Si foosolo debería funcionar con un argumento:

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

Si tiene necesidades más complejas, es fácil descomponer la validación de argumentos y la generación de mensajes como una función independiente. Puede hacer cosas más elaboradas mediante el uso de efectos secundarios enCondition más allá de solo generar mensajes, pero en mi opinión, la mayoría de ellos entran en la categoría de "pirateo de mala calidad" y deben evitarse si es posible.

Además, en la categoría "metaprogramación", si tiene un .marchivo de paquete de Mathematica ( ), puede usar el "HeldExpressions"elemento para obtener todas las expresiones del archivo HoldComplete. Esto hace que rastrear las cosas sea mucho más fácil que usar búsquedas basadas en texto. Desafortunadamente, no hay una manera fácil de hacer lo mismo con una computadora portátil, pero puede obtener todas las expresiones de entrada usando algo como lo siguiente:

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

Por último, puede usar el hecho de que Moduleemula cierres léxicos para crear el equivalente de los tipos de referencia. Aquí hay una pila simple (que utiliza una variación del Conditiontruco para el manejo de errores como un bono):

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]

¡Ahora puede imprimir los elementos de una lista en orden inverso de una manera innecesariamente complicada!

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

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

1
+1 para el HeldExpressionselemento en los paquetes, no lo sabía. Estaba generalmente importadores, tal como cadena y luego usar ToExpressioncon HoldCompletecuya última arg. Con respecto al uso Conditionde mensajes: esta ha sido una técnica estándar en la redacción de paquetes desde al menos 1994. Con respecto a la persistencia a través de Modulevars, he tenido una larga publicación sobre eso en Mathgroup hace un tiempo: groups.google.com/group/comp.soft- sys.math.mathematica / ... (mi tercera publicación en ese hilo), está en la misma línea y tiene enlaces a algunos ejemplos no triviales de uso.
Leonid Shifrin

@Leonid Shifrin: Elegí la Conditioncosa como tradición, probablemente de un compañero de trabajo, pero no me di cuenta de que era una técnica estándar. ¡El enlace sobre el uso de Modulesímbolos como tipos de referencia es interesante!
Pillsy

+1, nunca pensé en eso. Cuanto más aprendo sobre este idioma, más poderoso parece.
rcollyer

@Pillsy, ¿cuál es el propósito de hacer una pila de esa manera?
Mr.Wizard

@ Mr.Wizard: elegí una de las estructuras de datos mutables más simples que se me ocurrió para ilustrar la técnica.
Pillsy

11

Imprimir definiciones de símbolos del sistema sin contexto antepuesto

La contextFreeDefinition[]siguiente función intentará imprimir la definición de un símbolo sin el contexto más común antepuesto. La definición se puede copiar a Workbench y formatear para facilitar su lectura (selecciónela, haga clic con el botón derecho, Fuente -> Formato)

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

Advertencia: esta función no localiza variables de la misma manera Withy lo Modulehace, lo que significa que las construcciones de localización anidadas no funcionarán como se esperaba. withRules[{a -> 1, b -> 2}, With[{a=3}, b_ :> b]] se reemplace ay ben el anidado Withy Rule, mientras que Withno lo hace.

Esta es una variante de Withque usa reglas en lugar de =y :=:

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

Encontré esto útil mientras limpiaba el código escrito durante la experimentación y localizaba variables. De vez en cuando termino con listas de parámetros en forma de {par1 -> 1.1, par2 -> 2.2}. Con los withRulesvalores de los parámetros es fácil de inyectar en el código previamente escrito usando variables globales.

El uso es como With:

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

Antialiasing gráficos 3D

Esta es una técnica muy simple para antialias de gráficos 3D, incluso si su hardware de gráficos no lo admite de forma nativa.

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

Aquí hay un ejemplo:

Gráficos de Mathematica Gráficos de Mathematica

Tenga en cuenta que un valor grande no un tamaño de imagen grande tiende a exponer errores del controlador de gráficos o introducir artefactos.


Funcionalidad diff del portátil

La funcionalidad de diferencias de Notebook está disponible en el <<AuthorTools`paquete y (al menos en la versión 8) en el NotebookTools`contexto no documentado . Esta es una pequeña GUI para diferenciar dos cuadernos que están abiertos actualmente:

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

Gráficos de Mathematica


Todo sería bueno, pero esto realmente no localiza variables, como puede ver asignando say a = 3; b = 4;antes de su llamada de ejemplo y luego llamando withRules. Puede guardarlo en lugar de utilizar el siguiente: SetAttributes[withRules, HoldAll];withRules[rules_, expr_] := Unevaluated[expr] /. Unevaluated[rules]. Las diferencias con la semántica de wrt de Withentonces: 1. Ahora los lados de las reglas no son evalúan los 2. withRulesno resuelve los conflictos de nomenclatura con las construcciones de alcance interno como lo Withhace. El último es bastante serio: ser bueno o malo según el caso.
Leonid Shifrin

@Leonid Tienes toda la razón, parece que nunca aprendo a verificar el código correctamente antes de publicar ... cuando uso esto prácticamente nunca asigno valores a las variables, pero ese es un problema bastante serio, tienes razón. ¿Qué opinas sobre la versión corregida? (Realmente no me importa no manejar anidados Withs Esto no siempre funciona con las construcciones de orden interna de localización, ya sea, por ejemplo. With[{a=1}, Block[{a=2}, a]]¿Cree que hay una buena razón por la anidada. BlockNo hace Localizar allí, como anidado Withy Modulelo hace?)
Szabolcs

@Leonid no lo usé simplemente Unevaluated[rules]porque quería x -> 1+1evaluar el RHS.
Szabolcs

@Leonid En realidad tiene razón, el problema de localización anidada puede ser bastante grave. Creo que los Withs anidados son fáciles de detectar y evitar, pero los patrones no lo son: With[{a = 1}, a_ -> a]localiza el interior amientras withRulesque no. ¿Sabe si hay alguna forma de acceder al mecanismo de localización interna de Mathematica y crear nuevas construcciones (similares a Rule) que también se localizan? Probablemente borre esta respuesta más tarde, ya que es más peligrosa que útil, pero me gustaría jugar con ella un poco más primero.
Szabolcs

Creo que su uso InheritedBlockes bastante bueno y resuelve el problema con mucha elegancia. En cuanto a los conflictos de alcance, normalmente los enlaces para el alcance léxico ocurren en el "tiempo de enlace léxico", que es - antes del tiempo de ejecución, mientras que el alcance dinámico se une en el tiempo de ejecución, lo que podría explicarlo. Puede contrastar esto con el caso similar para Module, que permite un uso constructivo (consulte, por ejemplo, aquí stackoverflow.com/questions/7394113/… ). El problema es que Blocknecesita algún símbolo para ...
Leonid Shifrin

9

Las funciones recursivas puras ( #0) parecen ser uno de los rincones más oscuros del lenguaje. Aquí hay un par de ejemplos no triviales de su uso, donde esto es realmente útil (no es que no se puedan hacer sin él). La siguiente es una función bastante concisa y razonablemente rápida para encontrar componentes conectados en un gráfico, dada una lista de aristas especificadas como pares de vértices:

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

Lo que sucede aquí es que primero mapeamos un símbolo ficticio en cada uno de los números de vértice, y luego configuramos una forma que, dado un par de vértices {f[5],f[10]}, digamos, luego f[5]evaluaría f[10]. La función recursiva pura se usa como un compresor de ruta (para configurar la memorización de tal manera que, en lugar de cadenas largas como f[1]=f[3],f[3]=f[4],f[4]=f[2], ..., los valores memorizados se corrijan cada vez que se descubre una nueva "raíz" del componente. Esto da una aceleración significativa. Debido a que utilizamos la asignación, necesitamos que sea HoldAll, lo que hace que esta construcción sea aún más oscura y atractiva). Esta función es el resultado de una discusión de Mathgroup dentro y fuera de línea que involucra a Fred Simons, Szabolcs Horvat, DrMajorBob y los suyos de verdad. Ejemplo:

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>>}}

Ciertamente es mucho más lento que un incorporado, pero para el tamaño del código, bastante rápido sigue siendo IMO.

Otro ejemplo: aquí hay una realización recursiva Select, basada en listas vinculadas y funciones recursivas puras:

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

Por ejemplo,

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}}

Sin embargo, no es recursivo de cola correctamente, y volará la pila (bloqueará el núcleo) para listas más grandes. Aquí está la versión recursiva de la cola:

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]], {}]];

Por ejemplo,

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 función para los componentes conectados sigue siendo mi favorita :-)
Szabolcs

@Szabolcs Sí, es genial. Usted y Fred hicieron la mayor parte, Bobby y yo solo agregamos algunas mejoras, IIRC.
Leonid Shifrin

8

Esta es una receta del libro de Stan Wagon ... úsela cuando la trama incorporada se comporte de manera irregular debido a la falta de precisión

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

A menudo uso el siguiente truco de Kristjan Kannike cuando necesito un comportamiento "similar a un diccionario" de los valores bajos 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]

Cuando los resultados de la evaluación son confusos, a veces es útil volcar los pasos de evaluación en un archivo de texto

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

Una muestra de uso sería genial. Intenta publicar uno cuando tengas tiempo.
Dr. belisarius

¿Conoces a Kristjan? Solía ​​trabajar en el mismo grupo con él en Helsinki. Buen tipo, pequeño mundo.
Timo

No, encontró su código en la web. En realidad, traté de enviarle un correo electrónico para corregir un pequeño error en el código, pero el correo electrónico en su página web ya no funciona
Yaroslav Bulatov

8

Es posible ejecutar MathKernel en modo por lotes utilizando opciones de línea de comandos-batchinput-batchoutput no documentadas y :

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

(donde input.mestá el archivo de entrada por lotes que termina con el carácter de nueva línea, outputfile.txtes el archivo al que se redirigirá la salida).

En Mathematica v.> = 6, MathKernel tiene la opción de línea de comandos no documentada:

-noicon

que controla si MathKernel tendrá un icono visible en la barra de tareas (al menos en Windows).

FrontEnd (al menos desde v.5) tiene una opción de línea de comandos no documentada

-b

que deshabilita la pantalla de bienvenida y permite ejecutar Mathematica FrontEnd mucho más rápido

y opción

-directlaunch

que desactiva el mecanismo que inicia la versión de Mathematica más reciente instalada en lugar de iniciar la versión asociada con los archivos .nb en el registro del sistema.

Otra forma de hacer esto probablemente es :

En lugar de iniciar el binario Mathematica.exe en el directorio de instalación, inicie el binario Mathematica.exe en SystemFiles \ FrontEnd \ Binaries \ Windows. El primero es un simple programa de inicio que hace todo lo posible para redirigir las solicitudes de abrir cuadernos para ejecutar copias de la interfaz de usuario. La última es la interfaz de usuario binaria en sí.

Es útil combinar la última opción de línea de comandos con la configuración de la opción Global FrontEnd VersionedPreferences->True que deshabilita el intercambio de preferencias entre las diferentes versiones de Mathematica instaladas :

SetOptions[$FrontEnd, VersionedPreferences -> True]

(Lo anterior debe evaluarse en el Mathematica más reciente versión instalada).

En Mathematica 8, esto se controla en el cuadro de diálogo Preferencias, en el panel Sistema, en la configuración "Crear y mantener preferencias de front-end específicas de la versión" .

Es posible obtener una lista incompleta de las opciones de la línea de comandos de FrontEnd utilizando una clave no documentada -h(el código para Windows):

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

da:

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

Otras opciones incluyen:

-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

¿Hay otras opciones de línea de comandos potencialmente útiles de MathKernel y FrontEnd? Por favor comparte si lo sabes.

Pregunta relacionada .


"¿Bitness a juego?" Qué significa eso?
Mr.Wizard

@ Mr.Wizard Probablemente esta opción tiene sentido solo en sistemas de 64 bits en combinación con la opción -32y significa que la bitness del MathKernel utilizado por el FrontEnd coincidirá con la bitness del sistema operativo (64 bit). Parece que en otros casos esta opción no cambiará nada.
Alexey Popkov

7

Mis hacks favoritos son pequeñas macros generadoras de código que le permiten reemplazar un montón de comandos estándar por uno corto. Alternativamente, puede crear comandos para abrir / crear cuadernos.

Esto es lo que he estado usando durante un tiempo en mi flujo de trabajo diario de Mathematica. Me encontré realizando mucho lo siguiente:

  1. Haga que una computadora portátil tenga un contexto privado, cargue los paquetes que necesito, hágalo automáticamente
  2. Después de trabajar con este cuaderno por un tiempo, me gustaría hacer algunos cálculos de descarte en un cuaderno separado, con su propio contexto privado, mientras tengo acceso a las definiciones que he estado usando en el cuaderno "principal". Como configuré el contexto privado, esto requiere ajustar manualmente $ ContextPath

Hacer todo esto a mano una y otra vez es un dolor, ¡así que automaticemos! Primero, un código de utilidad:

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

Ahora, creemos una macro que va a poner las siguientes celdas en el cuaderno:

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

Y aquí está 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];
      ]
 ]

Ahora, cuando escribo, MyPrivatize[]crea el contexto privado y carga mi paquete estándar. Ahora creemos un comando que abrirá un nuevo bloc de notas con su propio contexto privado (para que pueda hackear allí con un abandono salvaje sin el riesgo de arruinar las definiciones), pero que tenga acceso a sus contextos actuales.

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

Lo bueno de esto es que, debido a que SelfDestruct, cuando se ejecuta el comando, no deja rastro en el cuaderno actual, lo cual es bueno, porque de lo contrario simplemente crearía desorden.

Para obtener puntos de estilo adicionales, puede crear activadores de palabras clave para estas macros InputAutoReplacements, pero lo dejaré como un ejercicio para el lector.


7

PutAppend con PageWidth -> Infinity

En Mathematica, el uso del PutAppendcomando es la forma más sencilla de mantener un archivo de registro en ejecución con resultados de cálculos intermedios. Pero utiliza la PageWith->78configuración predeterminada al exportar expresiones a un archivo, por lo que no hay garantía de que cada salida intermedia tome solo una línea en el registro.

PutAppendno tiene ninguna opción en sí, pero el seguimiento de sus evaluaciones revela que se basa en la OpenAppendfunción que tiene la PageWithopción y permite cambiar su valor predeterminado mediante el SetOptionscomando:

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

Entonces podemos PutAppendagregar solo una línea a la vez configurando:

SetOptions[OpenAppend, PageWidth -> Infinity]

ACTUALIZAR

Hay un error introducido en la versión 10 (corregido en la versión 11.3): SetOptionsya no afecta el comportamiento de OpenWritey OpenAppend.

Una solución alternativa es implementar su propia versión de PutAppendcon la PageWidth -> Infinityopción explícita :

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

Tenga en cuenta que también podemos implementarla WriteStringcomo se muestra en esta respuesta, pero en este caso será necesario convertir preliminarmente la expresión en la InputFormvía correspondiente ToString[expr, InputForm].


6

Yo estaba mirando a través de uno de mis paquetes para su inclusión en esta, y encontré algunos mensajes que he definido que funcionan de maravilla: Debug::<some name>. Por defecto, están apagados, por lo que no producen demasiados gastos generales. Pero, puedo llenar mi código con ellos y activarlos si necesito averiguar exactamente cómo se comporta un poco de código.


Desde La Ayuda> Desde la versión 2.0 (lanzada en 1991), la depuración ha sido reemplazada por Trace.
Dr. belisario

1
@belisarius, te perdiste el punto. No es ni el Debugni las Tracefunciones; Es un conjunto de mensajes que creé con los que puedo llenar mi código para encender / apagar a voluntad. Están precedidos por la palabra Debug, de la misma manera que un usagemensaje está precedido por el nombre de la función. Proporciona la misma funcionalidad que colocar un montón de coutsentencias en código c ++.
rcollyer

1
Oh, lo siento. Me confundí porque nunca me gradué de kindergarten por no aprender "Las capitales son para los países": D
Dr. belisarius

6

Una de las cosas que me molesta acerca de las construcciones de alcance incorporadas es que evalúan todas las definiciones de variables locales a la vez, por lo que no puede escribir, por ejemplo

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

Así que hace un tiempo se me ocurrió una macro llamada WithNest que te permite hacer esto. Me resulta útil, ya que te permite mantener localmente los enlaces variables sin tener que hacer algo como

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

Al final, la mejor manera que pude encontrar para hacer esto fue mediante el uso de un símbolo especial para facilitar la repetición de la lista de enlaces, y puse la definición en su propio paquete para mantener este símbolo oculto. ¿Quizás alguien tiene una solución más simple para este problema?

Si quieres probarlo, pon lo siguiente en un archivo llamado 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 publicó una versión de esto y hace referencia a su pregunta en MathGroup: stackoverflow.com/questions/4190845/custom-notation-question/…
Mr.Wizard

¡Gracias por señalar eso! Ha pasado un tiempo desde que miré estas cosas, y es interesante ver todos estos otros enfoques.
DGrady

5

Este fue escrito por Alberto Di Lullo, (que no parece estar en Stack Overflow).

CopyToClipboard, para Mathematica 7 (en Mathematica 8 está integrado)

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

Publicación original: http://forums.wolfram.com/mathgroup/archive/2010/Jun/msg00148.html

He encontrado esta rutina útil para copiar grandes números reales al portapapeles en forma decimal ordinaria. P.ejCopyToClipboard["123456789.12345"]

Cell[OutputFormData@expr] elimina cuidadosamente las comillas.


5

Este código crea una paleta que carga la selección en Stack Exchange como una imagen. En Windows, se proporciona un botón adicional que brinda una representación más fiel de la selección.

Copie el código en una celda del cuaderno y evalúe. Luego extraiga la paleta de la salida e instálela usandoPalettes -> Install Palette...

Si tiene algún problema, publique un comentario aquí. Descargue la versión del cuaderno aquí .


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

Estoy seguro de que muchas personas se han encontrado con la situación en la que ejecutan algunas cosas, al darse cuenta de que no solo bloquearon el programa, ¡sino que también no guardaron en los últimos 10 minutos!

EDITAR

Después de sufrir esto por un tiempo, un día descubrí que uno puede crear el guardado automático desde el código de Mathematica . Creo que usar ese auto-guardado me ha ayudado mucho en el pasado, y siempre sentí que la posibilidad en sí misma era algo que no mucha gente sabe que puede hacer.

El código original que utilicé está en la parte inferior. Gracias a los comentarios, descubrí que es problemático y que es mucho mejor hacerlo de forma alternativa, usando ScheduledTask(que solo funcionará en Mathematica 8).

El código para esto se puede encontrar en esta respuesta de Sjoerd C. de Vries (Dado que no estoy seguro de si está bien copiarlo aquí, lo dejo solo como un enlace).


La siguiente solución está usando Dynamic. Guardará el portátil cada 60 segundos, pero aparentemente solo si su celda es visible . Lo dejo aquí solo por razones de finalización. (y para usuarios de Mathematica 6 y 7)

/EDITAR

Para resolverlo, uso este código al comienzo de un cuaderno:

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

Esto ahorrará su trabajo cada 60 segundos.
Lo prefiero NotebookAutoSave[]porque se guarda antes de que se procese la entrada y porque algunos archivos tienen más texto que entrada.

Originalmente lo encontré aquí: http://en.wikipedia.org/wiki/Talk:Mathematica#Criticisms

Tenga en cuenta que una vez que se ejecuta esta línea, se guardará incluso si cierra y vuelve a abrir su archivo (siempre que la actualización dinámica esté habilitada).

Además, dado que no hay deshacer en Mathematica , tenga cuidado de no eliminar todo su contenido, ya que guardarlo lo hará irreversible (como medida de precaución, elimino este código de cada cuaderno terminado)


también puede guardarlo con un nombre diferente (por ejemplo, agregando la hora y fecha actuales al final del nombre del archivo) y tal vez en un directorio específico ("Copias de seguridad", por ejemplo). esto sería como una forma primitiva de versionado.
acl

Puede hacer algo como NotebookSave[SelectedNotebook[], "work-" <> IntegerString[i] <> ".nb"]; i++, pero creo que cualquier tipo de referencia al nombre del cuaderno actual será recursivo.
tsvikas

2
Pensé que los Dynamicobjetos solo se actualizan cuando son visibles, por lo que no estaría seguro de que este método funcionaría si, por ejemplo, desplaza el Dynamicobjeto fuera del área visible. Por otra parte, no lo he intentado. En cualquier caso, simplemente lo ofrecí como sugerencia.
acl

1
Puedes probar esto usando Dynamic[Refresh[i++, UpdateInterval -> 1, TrackedSymbols -> {}]]. Desplácese el número incremental desde la vista, espere un minuto, retroceda y vea que el número no se incrementa en 60. Acerca de UpdateInterval: esto generalmente se usa si es posible, pero si su código incluye variables que cambian, este cambio desencadena una nueva actualización antes de finaliza el intervalo. Pruebe la línea anterior sinTrackedSymbols
Sjoerd C. de Vries

1
@ j0ker5 Pruebe mi código anterior y podrá ver que UpdateInterval no siempre obliga a espaciar las actualizaciones con el intervalo especificado. Este código también muestra que Dynamic solo funciona si la celda en la que se encuentra está visible en la interfaz . Realmente se detiene en el momento en que está fuera de la vista. La gente realmente no debería confiar en este código para guardar sus archivos porque no lo hace. Es peligroso
Sjoerd C. de Vries


3

Me resulta muy útil al desarrollar paquetes para agregar este atajo de teclado a mi SystemFiles/FrontEnd/TextResources/Windows/KeyEventTranslations.trarchivo.

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

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

A continuación, cada vez Packagename.mque hago un PackagenameTest.nbcuaderno para probar y las primeras 2 celdas del cuaderno de prueba se configuran como celdas de inicialización. En la primera celda puse

Needs["PackageManipulations`"]

para cargar la muy útil biblioteca PackageManipulations que fue escrita por Leonid. La segunda celda contiene

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

que todos hacen la recarga real del paquete. Tenga en cuenta que las dos primeras líneas están ahí solo para Removetodos los símbolos, ya que me gusta mantener los contextos lo más limpios posible.

Luego, el flujo de trabajo para escribir y probar un paquete se convierte en algo como esto.

  1. Guardar cambios en Packagename.m.
  2. Ve PackagenameTest.nby haz CTRL + ALT + i.

Esto hace que las celdas de inicialización recarguen el paquete, lo que hace que las pruebas sean realmente simples.


1

La siguiente función format[expr_]se puede usar para sangrar / formatear mathematicaexpresiones sin formato que se extienden sobre una página

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]]
*)

ref: /codegolf/3088/indent-a-string-using-given-parentheses


¿Para qué estás usando esto en la práctica? El resultado es un poco "divertido" para ser legible cuando se aplica a su código o a los datos (listas, format@RandomInteger[10,{3,3}]): pastebin.com/nUT54Emq Dado que ya tiene los conceptos básicos y le interesa, ¿puede mejorar el código para producir un formato útil legible? Luego, el siguiente paso sería hacer un botón de pegar que creará una celda de entrada con un código de Mathematica muy bien sangrado (¡preferiblemente preservando los comentarios!) Vea también mi pregunta relacionada .
Szabolcs
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.