Cosa c'è nella borsa degli attrezzi Mathematica? [chiuso]


152

Sappiamo tutti che Mathematica è eccezionale, ma spesso manca anche di funzionalità critiche. Che tipo di pacchetti / strumenti / risorse esterni usi con Mathematica?

Modificherò (e inviterò chiunque altro a farlo) questo post principale per includere risorse che sono focalizzate sull'applicabilità generale nella ricerca scientifica e che quante più persone possibili troveranno utili. Sentiti libero di contribuire con qualsiasi cosa, anche piccoli frammenti di codice (come ho fatto sotto per una routine di temporizzazione).

Inoltre, sono benvenute funzionalità utili e non documentate in Mathematica 7 e oltre che ti sei trovato, o ricavato da un documento / sito.

Ti preghiamo di includere una breve descrizione o un commento sul perché qualcosa è eccezionale o sull'utilità fornita. Se si collega a libri su Amazon con collegamenti di affiliazione, si prega di menzionarlo, ad esempio, inserendo il proprio nome dopo il collegamento.


Pacchi:

  1. LevelSchemeè un pacchetto che espande notevolmente la capacità di Mathematica di produrre trame di bell'aspetto. Lo uso se non per nient'altro, quindi per il controllo molto, molto migliorato sulle zecche del telaio / assi. La sua versione più recente si chiama SciDraw e uscirà quest'anno.
  2. David Park's Presentation Package(US $ 50 - nessun addebito per gli aggiornamenti)
  3. Il grassmannOpspacchetto di Jeremy Michelson fornisce risorse per eseguire algebra e calcolo con variabili e operatori Grassmann che hanno relazioni di commutazione non banali.
  4. GrassmannAlgebraPacchetto e libro di John Brown per lavorare con le algebre di Grassmann e Clifford.
  5. RISC (Research Institute for Symbolic Computation) ha una varietà di pacchetti per Mathematica (e altre lingue) disponibili per il download. In particolare, v'è Theorema per lievitazione teorema automatizzata, e la moltitudine di pacchetti per somma simbolica, equazioni alle differenze, ecc alla pagina software del gruppo algoritmico combinatoria .

Utensili:

  1. MASHè l'eccellente script Perl di Daniel Reeves che essenzialmente fornisce supporto per script per Mathematica v7. (Ora integrato a partire da Mathematica 8 con l' -scriptopzione.)
  2. Un alternate Mathematica shellcon un input readline GNU (usando solo Python, * nix)
  3. Il pacchetto ColourMaths ti consente di selezionare visivamente parti di un'espressione e manipolarle. http://www.dbaileyconsultancy.co.uk/colour_maths/colour_maths.html

risorse:

  1. Il repository di Wolfram MathSourceha molti notebook utili se stretti per varie applicazioni. Dai un'occhiata anche alle altre sezioni come

  2. Il Wikibook di Mathematica .

Libri:

  1. Programmazione Mathematica: un'introduzione avanzata di Leonid Shifrin ( web,pdf ) è un must se vuoi fare qualcosa di più di For loop in Mathematica. Abbiamo il piacere di essere Leonidlui stesso a rispondere alle domande qui.
  2. Metodi quantistici con Mathematica di James F. Feagin ( amazon )
  3. Il libro di Mathematica di Stephen Wolfram ( amazon ) ( web)
  4. Profilo di Schaum ( amazon )
  5. Mathematica in Action di Stan Wagon ( amazon ) - 600 pagine di esempi chiari e arriva alla versione 7. di Mathematica Le tecniche di visualizzazione sono particolarmente buone, puoi vederne alcune sull'autore Demonstrations Page.
  6. Fondamenti di programmazione Mathematica di Richard Gaylord ( pdf) - Una buona introduzione concisa alla maggior parte di ciò che devi sapere sulla programmazione di Mathematica.
  7. Ricettario Mathematica di Sal Mangano pubblicato da O'Reilly 2010 832 pagine. - Scritto nel noto stile del ricettario O'Reilly: Problema - Soluzione. Per intermedi.
  8. Equazioni differenziali con Mathematica, 3a Ed. Elsevier 2004 Amsterdam di Martha L. Abell, James P. Braselton - 893 pagine Per i principianti, impara a risolvere DEs e Mathematica allo stesso tempo.

Funzionalità non documentate (o scarsamente documentate):

  1. Come personalizzare le scorciatoie da tastiera Mathematica. Vederethis question .
  2. Come ispezionare schemi e funzioni usati dalle stesse funzioni di Mathematica. Vederethis answer
  3. Come ottenere dimensioni coerenti per GraphPlots in Mathematica? Vederethis question .
  4. Come produrre documenti e presentazioni con Mathematica. Vedere this question.

2
Mathematica 8 è disponibile con una migliore integrazione degli script di shell. wolfram.com/mathematica/new-in-8/mathematica-shell-scripts
Joshua Martell

2
+1, per LevelScheme. È un po 'lento, a volte. Tuttavia, ha un metodo sano per creare segni di spunta ed è molto più facile creare layout degni di diario per la grafica Grid, o qualcosa del genere.
rcollyer,

2
Come proposto da Alexey nei commenti su questa domanda stackoverflow.com/questions/5152551/… , ho proposto qui la modifica del tag per Mathematica: meta.stackexchange.com/questions/81152/… . Dai un'occhiata e vota se sei d'accordo. Lo pubblico qui perché questa domanda ha molti favoriti nella comunità Mma qui.
Dr. belisarius,

1
Tutto, questa domanda dovrebbe davvero essere wiki della comunità per tutti i soliti motivi: non ha una risposta corretta ed è più un elenco di ogni altra cosa. Chiedo scusa a tutti coloro che hanno beneficiato profumatamente della reputazione di questa domanda.
rcollyer,

2
Queste risposte a questa domanda sono costruttive, dovrebbero essere riaperte.
MR

Risposte:


29

Ho detto questo prima, ma lo strumento che trovo più utile è un'applicazione di Reape Sowche imita / Estende il comportamento di GatherBy:

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

Ciò mi consente di raggruppare gli elenchi in base a qualsiasi criterio e trasformarli nel processo. Il modo in cui funziona è che una funzione di criteri ( f) tagga ciascun elemento nell'elenco, ogni elemento viene quindi trasformato da una seconda funzione fornita ( g) e l'output specifico è controllato da una terza funzione ( h). La funzione haccetta due argomenti: un tag e un elenco degli elementi raccolti che hanno quel tag. Gli articoli mantengono il loro ordine originale, quindi se lo imposti h = #1&ottieni un ordine non ordinato Union, come negli esempi per Reap. Tuttavia, può essere utilizzato per l'elaborazione secondaria.

Come esempio della sua utilità, ho lavorato con Wannier90 che genera l'hamiltoniano spazialmente dipendente in un file in cui ogni riga è un elemento diverso nella matrice, come segue

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

Per trasformare quella lista in una serie di matrici, ho raccolto tutte le liste secondarie che contengono la stessa coordinata, ho trasformato le informazioni dell'elemento in una regola (es. {I, j} -> Re [Hij] + I Im [Hij]), e poi ha trasformato le regole raccolte in un SparseArraytutto con una sola riga:

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

Onestamente, questo è il mio coltellino svizzero e rende le cose complesse molto semplici. La maggior parte dei miei altri strumenti sono in qualche modo specifici del dominio, quindi probabilmente non li pubblicherò. Tuttavia, molti, se non tutti, fanno riferimento SelectEquivalents.

Modifica : non imita completamente GatherByin quanto non può raggruppare più livelli dell'espressione nel modo più semplice GatherBypossibile. Tuttavia, Mapfunziona benissimo per la maggior parte di ciò di cui ho bisogno.

Esempio : @Yaroslav Bulatov ha chiesto un esempio autonomo. Ecco uno della mia ricerca che è stato notevolmente semplificato. Quindi, supponiamo di avere una serie di punti in un piano

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

e vorremmo ridurre il numero di punti con una serie di operazioni di simmetria. (Per i curiosi, stiamo generando il piccolo gruppo di ogni punto.) Per questo esempio, usiamo un asse di rotazione di quattro volte attorno all'asse z

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

Usando SelectEquivalentspossiamo raggruppare i punti che producono lo stesso insieme di immagini in queste operazioni, cioè sono equivalenti, usando quanto segue

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

che produce 3 liste secondarie contenenti i punti equivalenti. (Nota, Unionqui è assolutamente vitale in quanto assicura che la stessa immagine sia prodotta da ciascun punto. Inizialmente, l'ho usato Sort, ma se un punto giace su un asse di simmetria, è invariante sotto la rotazione attorno a quell'asse dando un'immagine extra di se stesso Quindi, Unionelimina queste immagini extra. Inoltre,GatherBy produrrebbe lo stesso risultato.) In questo caso, i punti sono già in una forma che userò, ma ho solo bisogno di un punto rappresentativo da ciascun raggruppamento e vorrei un conteggio dei punti equivalenti. Da allora, non ho bisogno di trasformare ogni punto, uso ilIdentityfunzione in seconda posizione. Per la terza funzione, dobbiamo stare attenti. Il primo argomento passato ad esso saranno le immagini dei punti sotto le rotazioni che per il punto {0,0,0}è un elenco di quattro elementi identici, e usarlo eliminerebbe il conteggio. Tuttavia, il secondo argomento è solo un elenco di tutti gli elementi che hanno quel tag, quindi conterrà solo {0,0,0}. Nel codice,

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

Nota, questo ultimo passaggio può essere realizzato altrettanto facilmente

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

Ma è facile con questo e l'esempio meno completo sopra per vedere come sono possibili trasformazioni molto complesse con un minimo di codice.


Il codice originale di Fortran77 è stato ristrutturato nel Giorno del Ringraziamento del 1996, e quindi per molti anni noto come turkey.f ...: D Grafica molto bella BTW. Mi sono ricordato del mostro di Falicov ...
Dr. belisarius,

@belisarius, non avevo letto la storia, è divertente. Ho appena iniziato a usare Wannier90, ma è uno dei Fortrancodici meglio organizzati e ben scritti che abbia mai visto. Mi fa quasi pensare di usare Fortran...
rcollyer

Mi chiedo se potresti aggiungere un esempio autonomo di SelectEquivalents in azione
Yaroslav Bulatov,

@Yaroslav Bulatov, ha aggiunto un esempio, per richiesta. Fammi sapere se questo aiuta. In caso contrario, vedremo cosa possiamo fare.
rcollyer,

Ottieni il segno di spunta in questa "domanda" per il contributo dello snippet di codice più interessante.
Timo,

57

Una delle cose belle dell'interfaccia per notebook Mathematica è che può valutare espressioni in qualsiasi lingua, non solo Mathematica. Come semplice esempio, prendere in considerazione la creazione di un nuovo tipo di cella di input Shell che passa l'espressione contenuta alla shell del sistema operativo per la valutazione.

Innanzitutto, definire una funzione che delega la valutazione di un comando testuale alla shell esterna:

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

Il secondo argomento è necessario e ignorato per ragioni che appariranno in seguito. Successivamente, vogliamo creare un nuovo stile chiamato Shell :

  1. Apri un nuovo quaderno.
  2. Seleziona la voce di menu Formato / Modifica foglio di stile ...
  3. Nella finestra di dialogo, accanto a Inserisci un nome stile: digitare Shell.
  4. Seleziona la parentesi di cella accanto al nuovo stile.
  5. Seleziona la voce di menu Cella / Mostra espressione
  6. Sovrascrivi l'espressione della cella con il testo del passaggio 6 riportato di seguito.
  7. Ancora una volta, selezionare la voce di menu Cella / Mostra espressione
  8. Chiudi la finestra di dialogo.

Utilizzare la seguente espressione di cella come testo passaggio 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 maggior parte di questa espressione è stata copiata direttamente dall'integrato stile del programma . Le modifiche principali sono queste righe:

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

Evaluatableabilita la funzionalità MAIUSC + INVIO per la cella. La valutazione chiamerà ilCellEvaluationFunction passaggio del contenuto della cella e del tipo di contenuto come argomenti ( shellEvaluateignora quest'ultimo argomento). CellFrameLabelsè solo una meraviglia che consente all'utente di identificare che questa cella è insolita.

Con tutto questo in atto, ora possiamo inserire e valutare un'espressione shell:

  1. Nel blocco note creato nei passaggi precedenti, creare una cella vuota e selezionare la parentesi di cella.
  2. Seleziona la voce di menu Formato / Stile / Shell .
  3. Digitare un comando di shell del sistema operativo valido nella cella (ad esempio 'ls' su Unix o 'dir' su Windows).
  4. Premere MAIUSC + INVIO.

È meglio mantenere questo stile definito in un foglio di stile posizionato centralmente. Inoltre, funzioni di valutazione come shellEvaluatesono meglio definite come stub usando DeclarePackage ininit.m . I dettagli di entrambe queste attività vanno oltre lo scopo di questa risposta.

Con questa funzionalità, è possibile creare notebook che contengono espressioni di input in qualsiasi sintassi di interesse. La funzione di valutazione può essere scritta in Mathematica pura o delegare una o tutte le parti della valutazione a un'agenzia esterna. Essere consapevoli del fatto che ci sono altri ganci che si riferiscono alla cella di valutazione, come CellEpilog, CellProloge CellDynamicExpression.

Un modello comune prevede la scrittura del testo dell'espressione di input in un file temporaneo, la compilazione del file in una lingua, l'esecuzione del programma e l'acquisizione dell'output per la visualizzazione finale nella cella di output. Ci sono molti dettagli da affrontare quando si implementa una soluzione completa di questo tipo (come catturare correttamente i messaggi di errore), ma si deve apprezzare il fatto che non è solo possibile fare cose del genere, ma pratiche.

Da un punto di vista personale, sono caratteristiche come questa che rendono l'interfaccia del notebook il centro del mio universo di programmazione.

Aggiornare

La seguente funzione di aiuto è utile per creare tali celle:

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

Viene utilizzato così:

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

Ora, se shellCell[]viene valutata, la cella di input verrà eliminata e sostituita con una nuova cella di input che ne valuta il contenuto come comando shell.


3
@WReach +100! Vorrei saperlo prima! Questa è roba molto utile, almeno per me. Grazie per la condivisione!
Leonid Shifrin,

Sembra piuttosto spiffero! CellEvaluationFunctionpenso che potrebbe essere usato anche per l'hacking della sintassi di basso livello.
Mr.Wizard,

@Leonid Almeno per FrontEnd, CellEvaluationFunctionl'amo che stavi cercando?
Mr.Wizard,

2
Inoltre: esiste un'altra Cellopzione correlata alla valutazione cellulare - Evaluator -> "EvaluatorName". Il significato di "EvaluatorName"potrebbe essere configurato tramite la finestra di dialogo Valutazione :: Opzioni di configurazione del kernel ... Continuo a non sapere se è possibile configurarlo a livello di codice ... Questa tecnica consente di utilizzare diversi MathKernel in diversi Cells in un Notebook. Questi MathKernels possono provenire da diverse versioni di Mathematica installate.
Alexey Popkov,

1
@Szabolcs Tutti i miei usi di questa tecnica implicano un approccio stdin _ / _ stdout come illustrato sopra, o una richiesta remota autonoma come una query SQL o un'operazione HTTP. Potresti provare a configurare un'app Web REPL di Python (come questa ) e interagire con essa usando Import, o magari avviando un processo Python esterno e comunicando attraverso i suoi flussi (ad esempio usando un ProcessBuilder Java ). Sono sicuro che esiste un modo migliore di Mathematica - sembra una buona domanda SO :)
WReach

36

Todd Gayley (Wolfram Research) mi ha appena inviato un bel trucco che permette di "avvolgere" le funzioni integrate con un codice arbitrario. Sento di dover condividere questo utile strumento. Quella che segue è la risposta di Todd sulla mia question.

Un po 'di storia interessante? allora. Da allora è stato usato molte volte da molte persone. È un po 'un trucco da insider, ma penso che sia giusto dire che è diventato il modo canonico di iniettare il tuo codice nella definizione di una funzione integrata. Fa bene il lavoro. Ovviamente puoi inserire la variabile $ inMsg in qualsiasi contesto privato desideri.

Unprotect[Message];

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

Protect[Message];

@Alexey ho difficoltà a capirlo. Potresti spiegare come funziona? Non dovrebbe esserci un Unprotect [Message] da qualche parte? E questo esempio non contiene ricorsione infinita? E, ! TrueQ [$ inMsg] ha senso con $ inMsg definito all'interno dell'ambito Block e non definito all'esterno di Block?
Sjoerd C. de Vries,

9
@Sjoerd Da quello che ho capito, Unprotectdeve davvero essere lasciato fuori. Il punto di Block(scoping dinamico) ed $inMsgè esattamente per prevenire la ricorsione infinita. Perché $inMsgall'esterno non è definito (questo è un requisito importante), inizialmente, TrueQvaluta Falsee entriamo nel corpo della funzione. Ma quando abbiamo la chiamata di funzione all'interno del corpo, la condizione viene valutata False(poiché la variabile è stata ridefinita da Block). Pertanto, la regola definita dall'utente non viene abbinata e viene invece utilizzata la regola integrata.
Leonid Shifrin,

1
@Leonid Grazie, ho capito ora. Molto intelligente!
Sjoerd C. de Vries,

1
Ho appena scoperto che questa tecnica è stata discussa da Robby Villegas di Wolfram Research alla Conferenza degli sviluppatori del 1999. Vedi il quaderno "Lavorare con le espressioni non valutate" pubblicato qui . In questo taccuino, Robby Villegas discute questo trucco nella sottosezione "Il mio blocco per intrappolare le chiamate nelle funzioni integrate".
Alexey Popkov,

1
@ Mr.Wizard Questo non è l'unico modo per farlo. Per molto tempo, ho usato una versione in cui la ridefinisci DownValuesin fase di esecuzione, puoi guardare questo post groups.google.com/group/comp.soft-sys.math.mathematica/… , per esempio ( SetDelayedridefinizione) . Ma il mio metodo è meno elegante, meno robusto, più soggetto a errori e rende la rottura dalla ricorsione molto meno banale da implementare. Quindi, nella maggior parte dei casi, il metodo descritto da @Alexey vince a mani basse.
Leonid Shifrin,

25

Questa non è una risorsa completa, quindi la sto lanciando qui nella sezione delle risposte, ma l'ho trovata molto utile per capire i problemi di velocità (che, sfortunatamente, è una grande parte di ciò che riguarda la programmazione di 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'utilizzo è quindi semplicemente timeAvg@funcYouWantToTest.

EDIT: Mr. Wizard ha fornito una versione più semplice che elimina Throwed Catched è un po 'più facile da analizzare:

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

EDIT: Ecco una versione da acl (presa da qui ):

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]

Fatto di nuovo e ancora ... tempo di entrare nella mia borsa. tnx!
Dr. belisarius,

1
Un problema con questo codice (beh, potrebbe essere questo il punto di vista di un perfezionista) è che possiamo catturare qualcosa che non abbiamo lanciato e interpretarlo come un risultato di tempismo errato. Entrambi Catche Throwavrebbero dovuto essere utilizzati con tag di eccezione univoci.
Leonid Shifrin,

2
Timo, sono contento che ti piaccia la mia interpretazione abbastanza da includerla. Grazie anche per avermi dato credito. Sono curioso di sapere come hai riformattato il mio codice. Non seguo particolari linee guida nel mio codice, oltre a rendere facile leggere me stesso; c'è una scuola di pensiero dietro la tua riformattazione o è solo una preferenza? Mathematica non incoraggia la formattazione precisa del codice a causa del modo in cui ridisegna l'input, ma la pubblicazione di codice qui mi sta facendo iniziare a pensarci. A proposito, penso che intendi " Throwe Catch" piuttosto che " Reape Sow".
Mr.Wizard,

1
@Simon, Mr.Wizard, io uso questo metodo per cronometrare versioni diverse di piccole funzioni che verranno chiamate molte volte. Non necessariamente in una struttura ad anello ma sicuramente all'interno di costrutti che MMA ottimizza. In questo contesto, l'esecuzione di un loop ha senso e le prestazioni saranno vicine all'applicazione della vita reale. Per temporizzare funzioni complesse di grandi dimensioni (forse anche intere celle di inizializzazione), il metodo di Simon darà un risultato migliore. Tutto sommato, però, sono più interessato ai valori relativi e entrambi i metodi dovrebbero funzionare lì.
Timo,

3
Ora c'è RepeatedTimingda fare questo.
masterxilo,

20

Internal`InheritedBlock

Recentemente ho appreso l'esistenza di una funzione così utile come Internal`InheritedBlock, da questo messaggio di Daniel Lichtblau nel newsgroup ufficiale.

A quanto ho capito, Internal`InheritedBlockconsente di passare una copia di una funzione in uscita all'interno Blockdell'ambito:

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]

Penso che questa funzione possa essere molto utile per tutti coloro che hanno bisogno di modificare temporaneamente le funzioni integrate!

Confronto con Block

Definiamo alcune funzioni:

a := Print[b]

Ora desideriamo passare una copia di questa funzione Blocknell'ambito. Il processo ingenuo non dà ciò che vogliamo:

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

During evaluation of In[9]:= b

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

Ora provando a usare la definizione ritardata nel primo argomento di Block(è anche una caratteristica non documentata):

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

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

During evaluation of In[3]:= b

Vediamo che in questo caso afunziona ma non abbiamo una copia dell'originale aall'interno Blockdell'ambito.

Ora proviamo Internal`InheritedBlock:

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

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

Abbiamo una copia della definizione originale per aall'interno Blockdell'ambito e possiamo modificarla nel modo che desideriamo senza influire sulla definizione globale per a!


+1 Molto utile! Un altro strumento nella borsa e 10 punti più vicini al privilegio Modifica per te.
Mr.Wizard,

Per me questo appare come una variante della valutazione iniziale o tardiva o no e completa.
user2432923

19

Mathematica è uno strumento affilato, ma può tagliarti con il suo comportamento in qualche modo non tipizzato e valanghe di messaggi diagnostici criptici . Un modo per gestirlo è definire le funzioni seguendo questo idioma:

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

Questo è un sacco di scaldavivande, che spesso sono tentato di saltare. Soprattutto durante la prototipazione, cosa che succede molto in Mathematica. Quindi, uso una macro chiamata defineche mi permette di rimanere disciplinato, con molto meno boilerplate.

Un utilizzo di base di defineè come questo:

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

fact[5]

120

All'inizio non sembra molto, ma ci sono alcuni vantaggi nascosti. Il primo servizio che definefornisce è che si applica automaticamenteClearAll al simbolo che viene definito. Ciò garantisce che non vi siano definizioni rimanenti: un evento comune durante lo sviluppo iniziale di una funzione.

Il secondo servizio è che la funzione che si sta definendo viene automaticamente "chiusa". Con questo intendo che la funzione emetterà un messaggio e si interromperà se viene invocata con un elenco di argomenti che non corrisponde a una delle definizioni:

fact[-1]

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

Questo è il valore principale di define , che rileva una classe di errori molto comune.

Un'altra comodità è un modo conciso per specificare gli attributi sulla funzione che si sta definendo. Facciamo la funzione Listable:

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

fact[{3, 5, 8}]

{6, 120, 40320}

Oltre a tutti gli attributi normali, defineaccetta un attributo aggiuntivo chiamato Open. Ciò impedisce definedi aggiungere la definizione di errore generale alla funzione:

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

successor /@ {1, "hi"}

{2, successor["hi"]}

È possibile definire più attributi per una funzione:

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

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

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

Senza ulteriori indugi, ecco la definizione di 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'implementazione esposta non supporta né valori positivi né curring, né schemi più generali della semplice definizione di funzione. Resta comunque utile.


2
+1 - questa è roba davvero utile. Ho usato strumenti simili. Le macro (così come l'introspezione e altre tecniche di meta-programmazione) possono essere molto potenti, ma sembrano essere poco apprezzate in genere all'interno della comunità Mathematica, o almeno questa è stata la mia impressione finora.
Leonid Shifrin,

Ho appena definito qualcosa di simile. +1 per il supporto di CompoundExpression per l'esecuzione di più definizioni, Abort [] (sembra migliore di ancora più messaggi) e Open (utile per es. Costruttori).
masterxilo,

16

Inizia senza un taccuino vuoto aperto

Mi ha infastidito l'avvio di Mathematica con un taccuino vuoto aperto. Potrei chiudere questo quaderno con uno script, ma si aprirà comunque brevemente. Il mio trucco è creare un file Invisible.nbcontenente:

Notebook[{},Visible->False]

E aggiungi questo al mio Kernel\init.m:

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

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

Ora inizio Mathematica aprendo Invisible.nb

Potrebbe esserci un modo migliore, ma questo mi è servito bene.


Personalizzato FoldeFoldList

Fold[f, x] è reso equivalente a Fold[f, First@x, Rest@x]

Per inciso, credo che questo possa trovare la sua strada in una versione futura di Mathematica.

Sorpresa! Questo è stato implementato, sebbene attualmente non sia documentato. Sono stato informato che è stato implementato nel 2011 da Oliver Ruebenkoenig, apparentemente non molto tempo dopo averlo pubblicato. Grazie 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]

Aggiornato per consentire questo:

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

"Partizione dinamica"

Vedere post # 7512 di Mathematica.SE per una nuova versione di questa funzione.

Spesso voglio partizionare un elenco secondo una sequenza di lunghezze.

esempio di pseudo-codice:

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

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

Ho pensato a questo:

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

Che poi ho completato con questo, incluso il test degli argomenti:

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

Il terzo argomento controlla cosa succede agli elementi oltre la specifica di divisione.


I trucchi di Mathematica di Szabolcs

Quello che uso più frequentemente è la tavolozza Incolla dati tabulari

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

Modifica i dati esterni dall'interno Compile

Di recente Daniel Lichtblau ha mostrato questo metodo che non avevo mai visto prima. A mio avviso estende notevolmente l'utilità diCompile

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 buona collezione! Per quanto riguarda le modifiche esterne dall'interno Compile- il mio intero post qui: stackoverflow.com/questions/5246330/… , è stato quello di mostrare questa possibilità in un ambiente non banale (c'era già una soluzione più breve e più rapida al problema in questione pubblicato già lì) . IMO, la più grande vittoria qui è la capacità di emulare pass-by-reference e suddividere grandi funzioni compilate in blocchi più gestibili e riutilizzabili.
Leonid Shifrin,

1
È inoltre possibile regolare le informazioni sintassi Fold e FoldList nella vostra nuova definizione: SyntaxInformation [Piega] = { "ArgumentsPattern" -> {_, . , _}}; SyntaxInformation [FoldList] = {"ArgumentsPattern" -> {_, _., {_ }}};
Faysou,

14

Problemi generali e soluzioni di esportazione PDF / EMF

1) È completamente inaspettato e privo di documenti, ma Mathematica esporta e salva la grafica in formato PDF ed EPS usando una serie di definizioni di stile che differiscono da quella usata per visualizzare i Notebook sullo schermo. Per impostazione predefinita, i notebook sono visualizzati sullo schermo nell'ambiente di stile "Funzionante" (che è il valore predefinito per l' opzione ScreenStyleEvironmentglobale $FrontEnd) ma sono stampati nell'ambiente di "Printout"stile (che è il valore predefinito per l' opzione PrintingStyleEnvironmentglobale $FrontEnd). Quando si esporta grafica in formati raster come GIF e PNG o in formato EMF, Mathematica genera una grafica che assomiglia esattamente a quella di Notebook. Sembra che il ambiente di stile viene utilizzato per impostazione predefinita"Working"in questo caso viene utilizzato l'ambiente di stile. Ma non è il caso di esportare / salvare qualcosa in formato PDF o EPS! In questo caso "Printout"ciò differisce profondamente dall'ambiente di stile "Working". Innanzitutto, l' "Printout"ambiente di stile è impostato Magnificationsull'80% . In secondo luogo, utilizza i propri valori per le dimensioni dei caratteri di stili diversi e ciò comporta modifiche incoerenti della dimensione dei caratteri nel file PDF genarizzato rispetto alla rappresentazione originale sullo schermo. Quest'ultimo può essere chiamato fluttuazioni FontSize che sono molto fastidiose. Fortunatamente questo può essere evitato impostando l' opzione PrintingStyleEnvironmentglobale $FrontEndsu "Funzionante" :

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

2) Il problema comune nell'esportazione in formato EMF è che la maggior parte dei programmi (non solo Mathematica ) genera un file che ha un bell'aspetto alla dimensione predefinita ma diventa brutto quando lo ingrandisci. È perché i metafile vengono campionati con fedeltà di risoluzione dello schermo . La qualità del file EMF generato può essere migliorata Magnifyinserendo l'oggetto grafico originale in modo che l'esattezza del campionamento della grafica originale diventi molto più precisa. Confronta due file:

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

Se inserisci questi file in Microsoft Word e ingrandisci, vedrai che la prima "a" ha il dente di sega su di essa mentre la seconda no (testata con Mathematica 6).

Un altro modo è ImageResolutionstato suggerito da Chris Degnen (questa opzione ha effetto almeno a partire da Mathematica 8):

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

3) In Mathematica abbiamo tre modi per convertire grafica in metafile: via Exportper "EMF"(modo fortemente raccomandato: produce metafile con la massima qualità possibile), tramite Save selection As...la voce di menu ( produce molto minore cifra precisa , non raccomandato) e tramite Edit ► Copy As ► Metafilela voce di menu ( consiglio vivamente contro questa via ).


13

A grande richiesta, il codice per generare il grafico dei 10 migliori risponditori SO (tranne le annotazioni ) utilizzando l' API SO .

inserisci qui la descrizione dell'immagine

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 ha pubblicato una domanda chiedendo quasi questo codice esatto. Forse è più appropriato lì, con un paio di modifiche per soddisfare la domanda. Sarei davvero degno rappresentante, al contrario di questa domanda.
rcollyer,

@rcollyer ha ragione. Questa è "Community Wiki"
Dr. belisarius,

@belisarius L'ho appena copiato nella risposta alla domanda di Brett ...
Sjoerd C. de Vries,

@Sjoerd Il tuo diagramma qui non si aggiorna automaticamente.
Dr. belisarius,

@belisarius In realtà speravo che avresti assunto quel compito su di te ... ;-)
Sjoerd C. de Vries,

13

Espressioni nella cache

Trovo queste funzioni molto utili per memorizzare nella cache qualsiasi espressione. La cosa interessante qui per queste due funzioni è che l'espressione mantenuta stessa viene utilizzata come chiave dell'hashtable / simbolo Cache o CacheIndex, rispetto alla nota memoizzazione in matematica in cui è possibile memorizzare nella cache il risultato solo se la funzione è definita come f [x_]: = f [x] = ... Quindi puoi memorizzare nella cache qualsiasi parte di un codice, questo è utile se una funzione deve essere chiamata più volte ma solo alcune parti del codice non devono essere ricalcolate.

Memorizzare un'espressione nella cache indipendentemente dai suoi argomenti.

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

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

La seconda volta che l'espressione restituisce 6 senza attendere.

Per memorizzare nella cache un'espressione usando un'espressione alias che può dipendere da un argomento dell'espressione memorizzata nella cache.

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

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

Se expr richiede del tempo per il calcolo, è molto più veloce valutare {"f", 2} ad esempio per recuperare il risultato memorizzato nella cache.

Per una variazione di queste funzioni al fine di avere una cache localizzata (ovvero la memoria cache viene automaticamente rilasciata all'esterno del costrutto Block) vedere questo post Evitare ripetute chiamate a Interpolazione

Eliminazione di valori memorizzati nella cache

Per eliminare i valori memorizzati nella cache quando non si conosce il numero di definizioni di una funzione. Ritengo che le definizioni abbiano un vuoto da qualche parte nei loro argomenti.

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

Per cancellare i valori memorizzati nella cache quando si conosce il numero di definizioni di una funzione (va leggermente più veloce).

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

Questo utilizza il fatto che le definizioni di una funzione sono alla fine del loro elenco DownValues, i valori memorizzati nella cache sono precedenti.

Utilizzo di simboli per memorizzare dati e funzioni simili a oggetti

Anche qui ci sono funzioni interessanti per usare simboli come oggetti.

È già noto che è possibile archiviare i dati in simboli e accedervi rapidamente utilizzando DownValues

mysymbol["property"]=2;

Puoi accedere all'elenco di chiavi (o proprietà) di un simbolo usando queste funzioni in base a ciò che dreeves ha inviato in un post su questo sito:

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

Uso molto questa funzione per visualizzare tutte le informazioni contenute nei DownValues ​​di un simbolo:

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

Infine ecco un modo semplice per creare un simbolo che si comporta come un oggetto nella programmazione orientata agli oggetti (riproduce semplicemente il comportamento più elementare di OOP ma trovo che la sintassi sia 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
  ];

Le proprietà sono memorizzate come DownValues ​​e metodi come Upvalues ​​ritardati nel simbolo creato dal Modulo che viene restituito. Ho trovato la sintassi per function2 che è la solita sintassi OO per le funzioni in struttura dei dati dell'albero in Mathematica .

Per un elenco dei tipi di valori esistenti di ciascun simbolo, vedere http://reference.wolfram.com/mathematica/tutorial/PatternsAndTransformationRules.html e http://www.verbeia.com/mathematica/tips/HTMLLinks/Tricks_Misc_4.html .

Ad esempio, prova questo

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

Puoi andare oltre se vuoi emulare l'ereditarietà degli oggetti usando un pacchetto chiamato InheritRules disponibile qui http://library.wolfram.com/infocenter/MathSource/671/

È inoltre possibile memorizzare la definizione della funzione non in newObject ma in un simbolo di tipo, quindi se NewObject restituisce il tipo [newObject] anziché newObject è possibile definire la funzione e la funzione2 in questo modo al di fuori di NewObject (e non all'interno) e avere lo stesso utilizzo di prima .

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

Utilizzare UpValues ​​[tipo] per vedere che funzione e funzione2 sono definite nel simbolo del tipo.

Ulteriori idee su quest'ultima sintassi sono presentate qui https://mathematica.stackexchange.com/a/999/66 .

Versione migliorata di SelectEquivalents

@rcollyer: Mille grazie per aver portato in superficie SelectEquivalents, è una funzione straordinaria. Ecco una versione migliorata di SelectEquivalents sopra elencata con più possibilità e opzioni di utilizzo, questo ne semplifica l'utilizzo.

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

Ecco alcuni esempi di come è possibile utilizzare questa versione:

Utilizzando Mathematica Raccogli / Raccogli correttamente

Come eseguiresti una funzione di tabella pivot in Mathematica?

Algoritmo di binning 2D veloce Mathematica

Internal`Bag

Daniel Lichtblau descrive qui un'interessante struttura interna di dati per elenchi in crescita.

Implementazione di un Quadtree in Mathematica

Funzioni di debug

Questi due post indicano funzioni utili per il debug:

Come eseguire il debug quando si scrivono codici piccoli o grandi usando Mathematica? banco di lavoro? debugger mma? o qualcos'altro?(ShowIt)

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

Ecco un'altra funzione basata su Reap e Sow per estrarre espressioni da diverse parti di un programma e memorizzarle in un simbolo.

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

Ecco un esempio

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

Altre risorse

Ecco un elenco di collegamenti interessanti a scopo di apprendimento:

Una raccolta di risorse per l'apprendimento di Mathematica

Aggiornato qui: https://mathematica.stackexchange.com/a/259/66


Correlati: " Il modo migliore per costruire una funzione con memoria ". WReach ha fornito un fantastico esempio di semplice funzione che non solo ricorda i suoi valori ma li scrive anche su un file e li legge al riavvio.
Alexey Popkov,

1
Correlati: " Mathematica: come cancellare la cache per un simbolo, ovvero DownValues ​​senza pattern non impostati ". Questa domanda mostra come cancellare la cache usando la f[x_] := f[x] = some codememoization standard .
Simon,

7
+1 C'è una bella convenienza di notazione che elimina la necessità di ripetere il lato sinistro della definizione di una funzione di memorizzazione nella cache, ad esempio: c:Cache[expr_] := c = expr.
Leggi il

Bella variante di SelectEquivalents. Penso che manterrei TagOnElementcome secondo parametro predefinito Identitycome è il più usato di loro, però. Non penso che avrei incluso FinalOp, in quanto può essere gestito all'interno OpOnTaggedElems. Accorcerei anche i nomi delle opzioni, in quanto la loro lunghezza rende difficile scrivere. Provate TagFunction, TransformElement, TransformResults, e TagPatterninvece. Entrambi, TagPatterne MapLevelsono grandi aggiunte alla funzionalità e una buona riscrittura, nel complesso.
rcollyer,

Grazie per il tuo commento rcollyer. L'ho preso in considerazione e migliorato anche la leggibilità del codice. Conservo FinalFunction perché funziona sul risultato di Reap, ad esempio se si desidera ordinare il risultato finale in base ai tag se vengono conservati.
faysou,

12

Le mie funzioni di utilità (le ho integrate in MASH, che è menzionato nella domanda):

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 trucco che ho usato, che ti consente di emulare il modo in cui la maggior parte delle funzioni integrate funziona con argomenti non validi (inviando un messaggio e restituendo l'intero modulo non valutato) sfrutta una stranezza del modo in Conditioncui funziona quando viene utilizzato in una definizione. Se foodovrebbe funzionare solo con un argomento:

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

Se hai esigenze più complesse, è facile fattorizzare la convalida degli argomenti e la generazione di messaggi come funzione indipendente. Puoi fare cose più elaborate usando effetti collaterali Conditionoltre a generare messaggi, ma a mio avviso la maggior parte di essi rientra nella categoria "squallido hack" e dovrebbe essere evitata se possibile.

Inoltre, nella categoria "metaprogrammazione", se si dispone di un .mfile package ( ) di Mathematica , è possibile utilizzare l' "HeldExpressions"elemento per ottenere tutte le espressioni contenute nel file HoldComplete. Ciò rende molto più semplice rintracciare le cose rispetto all'utilizzo di ricerche basate su testo. Sfortunatamente, non esiste un modo semplice per fare la stessa cosa con un notebook, ma puoi ottenere tutte le espressioni di input usando qualcosa di simile al seguente:

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

Infine, puoi utilizzare il fatto che Moduleemula le chiusure lessicali per creare l'equivalente dei tipi di riferimento. Ecco un semplice stack (che utilizza una variante del Conditiontrucco per la gestione degli errori come bonus):

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]

Ora puoi stampare gli elementi di un elenco in ordine inverso in modo inutilmente contorto!

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

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

1
+1 per HeldExpressionselemento nei pacchetti, non ne era a conoscenza. Di solito stavo importando come stringa e poi usando ToExpressioncon HoldCompletecome ultimo argomento. Per quanto riguarda l'utilizzo Conditionper i messaggi - questa è stata una tecnica standard nella scrittura di pacchetti almeno dal 1994. Per quanto riguarda la persistenza attraverso vari Module- Ho avuto un lungo post su quello su Mathgroup qualche tempo fa: groups.google.com/group/comp.soft- sys.math.mathematica /… (il mio terzo post in quella discussione), questo è sulla stessa linea e ha collegamenti ad alcuni esempi non banali di utilizzo.
Leonid Shifrin,

@Leonid Shifrin: ho preso la Conditioncosa come tradizione, probabilmente da un collega, ma non mi ero reso conto che fosse una tecnica standard. Il link sull'uso dei Modulesimboli come tipi di riferimento è interessante!
Pillsy,

+1, non ci ho mai pensato. Più imparo su questa lingua, più sembra potente.
rcollyer,

@Pillsy qual è lo scopo di fare uno stack in quel modo?
Mr.Wizard,

@ Mr.Wizard: ho appena scelto una delle strutture di dati mutabili più semplici a cui potrei pensare per illustrare la tecnica.
Pillsy,

11

Stampa delle definizioni dei simboli di sistema senza contesto anteposto

La contextFreeDefinition[]funzione seguente tenterà di stampare la definizione di un simbolo senza anteporre il contesto più comune. La definizione può quindi essere copiata su Workbench e formattata per essere leggibile (selezionarla, fare clic con il tasto destro, Origine -> 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 []

Avvertenza: questa funzione non localizza le variabili nello stesso modo Withe Modulefa, il che significa che i costrutti di localizzazione nidificati non funzioneranno come previsto. withRules[{a -> 1, b -> 2}, With[{a=3}, b_ :> b]] si sostituirà ae bnel nidificato Withe Rule, pur Withnon farlo.

Questa è una variante Withche utilizza le regole anziché =e :=:

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

L'ho trovato utile durante la pulizia del codice scritto durante la sperimentazione e la localizzazione delle variabili. Di tanto in tanto finisco con elenchi di parametri sotto forma di {par1 -> 1.1, par2 -> 2.2}. Con withRulesi valori dei parametri è facile iniettare nel codice precedentemente scritto usando variabili globali.

L'utilizzo è proprio come With:

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

Grafica 3D antialiasing

Questa è una tecnica molto semplice per antialias grafica 3D anche se l'hardware grafico non la supporta in modo nativo.

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

Ecco un esempio:

Grafica Mathematica Grafica Mathematica

Si noti che un valore elevato no una dimensione di immagine grande tende a esporre bug del driver grafico o introdurre artefatti.


Funzionalità diff Notebook

La funzionalità diff Notebook è disponibile nel <<AuthorTools`pacchetto e (almeno nella versione 8) nel NotebookTools`contesto non documentato . Questa è una piccola interfaccia grafica per diffondere due notebook attualmente aperti:

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

Grafica Mathematica


Tutto sarebbe bello, ma questo non localizza realmente le variabili, come puoi vedere assegnando dire a = 3; b = 4;prima della tua chiamata di esempio e quindi chiamando withRules. È possibile salvare dal invece utilizzando la seguente: SetAttributes[withRules, HoldAll];withRules[rules_, expr_] := Unevaluated[expr] /. Unevaluated[rules]. Le differenze rispetto alla semantica di Withallora: 1. i lati delle regole ora non vengono valutati 2. withRulesnon risolve i conflitti di denominazione con costrutti di scoping interni come Withfa. L'ultimo è piuttosto serio: essere una cosa buona o cattiva a seconda del caso.
Leonid Shifrin,

@Leonid Hai perfettamente ragione, sembra che non impari mai a controllare correttamente il codice prima di pubblicare ... quando lo uso praticamente non assegno mai valori alle variabili, ma questo è un problema piuttosto serio, hai ragione. Cosa ne pensi della versione corretta? (Non mi interessa davvero non gestire i nidificati With. Ciò non sempre funziona con i costrutti di localizzazione incorporati, ad es With[{a=1}, Block[{a=2}, a]]. Pensi che ci sia una buona ragione per cui il nidificato Blocknon si localizza lì, come il nidificato Withe lo Modulefa?)
Szabolcs,

@Leonid Non ho semplicemente usato Unevaluated[rules]perché volevo x -> 1+1valutare l'RHS.
Szabolcs,

@Leonid Hai ragione, il problema della localizzazione nidificata può essere piuttosto grave. Penso che i nidificati Withsiano facili da individuare ed evitare, ma i modelli non lo sono: With[{a = 1}, a_ -> a]localizza l'interiore amentre withRulesno. Sai se esiste un modo per accedere al meccanismo di localizzazione interna di Mathematica e creare nuovi costrutti (simili a Rule) che localizzano anche? Probabilmente eliminerò questa risposta in un secondo momento poiché è più pericolosa che utile, ma mi piacerebbe giocarci un po 'di più prima.
Szabolcs,

Penso che il tuo uso InheritedBlocksia piuttosto interessante e risolva il problema in modo molto elegante. Per quanto riguarda i conflitti di scoping, normalmente i vincoli per scoping lessicale si verificano in "tempo di legame lessicale", ovvero prima del runtime, mentre il scoping dinamico si lega al runtime, il che potrebbe spiegarlo. Puoi contrastare questo con il caso simile per Module, che consente un uso costruttivo (vedi ad esempio qui stackoverflow.com/questions/7394113/… ). Il problema è che ha Blockbisogno di un simbolo per ...
Leonid Shifrin,

9

Le funzioni pure ricorsive ( #0) sembrano essere uno degli angoli più oscuri della lingua. Ecco un paio di esempi non banali del loro uso, dove questo è davvero utile (non che non possano essere fatti senza di esso). Quella che segue è una funzione abbastanza concisa e ragionevolmente veloce per trovare componenti collegati in un grafico, dato un elenco di spigoli specificati come coppie di vertici:

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

Quello che succede qui è che prima mappiamo un simbolo fittizio su ciascuno dei numeri di vertice, e quindi impostiamo un modo che, data una coppia di vertici {f[5],f[10]}, diciamo, quindi f[5]valuterebbe f[10]. La funzione pura ricorsiva viene utilizzata come compressore di percorso (per impostare la memoizzazione in modo tale che invece di catene lunghe come f[1]=f[3],f[3]=f[4],f[4]=f[2], ..., i valori memorizzati vengano corretti ogni volta che viene scoperta una nuova "radice" del componente. Ciò consente una notevole accelerazione. Poiché usiamo il compito, abbiamo bisogno che sia HoldAll, il che rende questo costrutto ancora più oscuro e più attraente). Questa funzione è il risultato della discussione online e offline di Mathgroup che coinvolge Fred Simons, Szabolcs Horvat, DrMajorBob e il tuo. Esempio:

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

È certamente molto più lento di un built-in, ma per le dimensioni del codice, abbastanza veloce ancora IMO.

Un altro esempio: ecco una realizzazione ricorsiva di Select, basata su liste collegate e funzioni pure ricorsive:

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

Per esempio,

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

Tuttavia non è propriamente ricorsivo di coda e farà esplodere lo stack (crash del kernel) per elenchi più grandi. Ecco la versione ricorsiva della coda:

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

Per esempio,

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 funzione per i componenti collegati è ancora una delle mie preferite :-)
Szabolcs,

@Szabolcs Sì, è abbastanza bello. Tu e Fred avete fatto la maggior parte, io e Bobby abbiamo aggiunto solo alcuni perfezionamenti, IIRC.
Leonid Shifrin,

8

Questa è la ricetta del libro di Stan Wagon ... usala quando il diagramma incorporato si comporta in modo irregolare a causa della mancanza di precisione

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

Uso spesso il seguente trucco di Kristjan Kannike quando ho bisogno di un comportamento "simile a un dizionario" dai valori negativi di 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]

Quando i risultati della valutazione sono confusi, a volte aiuta a scaricare i passaggi della valutazione in un file di testo

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 campione di utilizzo sarebbe fantastico. Prova a postarne uno quando hai tempo.
Dr. belisarius,

Conosci Kristjan? Lavoravo nello stesso gruppo con lui a Helsinki. Bel ragazzo, piccolo mondo.
Timo,

No, ho trovato il suo codice sul web. In realtà, ho provato a inviargli un'e-mail per correggere un piccolo bug nel codice, ma l'e-mail sulla sua pagina web non funziona più
Yaroslav Bulatov,

8

È possibile eseguire MathKernel in modalità batch utilizzando le opzioni della riga di comando-batchinput-batchoutput non documentate e :

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

(dove si input.mtrova il file di input batch che termina con il carattere di nuova riga, outputfile.txtè il file a cui verrà reindirizzato l'output).

In Mathematica v.> = 6 il MathKernel ha l'opzione della riga di comando non documentata:

-noicon

che controlla se MathKernel avrà l'icona visibile sulla barra delle applicazioni (almeno in Windows).

FrontEnd (almeno dalla v.5) ha un'opzione della riga di comando non documentata

-b

che disabilita la schermata iniziale e consente di eseguire Mathematica FrontEnd molto più velocemente

e opzione

-directlaunch

che disabilita il meccanismo che avvia la versione più recente di Mathematica installata invece di avviare la versione associata ai file .nb nel registro di sistema.

Un altro modo per farlo probabilmente è :

Invece di avviare il binario Mathematica.exe nella directory di installazione, avviare il binario Mathematica.exe in SystemFiles \ FrontEnd \ Binaries \ Windows. Il primo è un semplice programma di avvio che fa del suo meglio per reindirizzare le richieste di apertura dei notebook alle copie in esecuzione dell'interfaccia utente. Quest'ultimo è lo stesso binario dell'interfaccia utente.

È utile combinare l'ultima opzione della riga di comando con l'impostazione dell'opzione FrontEnd globale VersionedPreferences->True che disabilita la condivisione delle preferenze tra le diverse versioni di Mathematica installate :

SetOptions[$FrontEnd, VersionedPreferences -> True]

(Quanto sopra dovrebbe essere valutato nell'ultima versione di Mathematica installata.)

In Mathematica 8 questo è controllato nella finestra di dialogo Preferenze, nel pannello Sistema, sotto l'impostazione "Crea e mantieni le preferenze del front-end specifiche della versione" .

È possibile ottenere un elenco incompleto delle opzioni della riga di comando di FrontEnd utilizzando la chiave non documentata -h(il codice per Windows):

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

dà:

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

Altre opzioni includono:

-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

Esistono altre opzioni della riga di comando potenzialmente utili di MathKernel e FrontEnd? Per favore condividi se lo sai.

Domanda correlata .


"testimone corrispondente?" Cosa significa?
Mr.Wizard,

@ Mr.Wizard Probabilmente questa opzione ha senso solo con i sistemi a 64 bit in combinazione con l'opzione -32e significa che il testimone del MathKernel usato da FrontEnd corrisponderà al testimone del sistema operativo (64 bit). Sembra che in altri casi questa opzione non cambierà nulla.
Alexey Popkov,

7

I miei hack preferiti sono piccole macro per la generazione di codice che ti consentono di sostituire un gruppo di comandi standard di plateplate con uno breve. In alternativa, è possibile creare comandi per l'apertura / la creazione di blocchi appunti.

Ecco cosa ho usato per un po 'nel mio flusso di lavoro quotidiano di Mathematica. Mi sono ritrovato a eseguire molto quanto segue:

  1. Fai in modo che un notebook abbia un contesto privato, carica i pacchetti di cui ho bisogno, rendilo automatico.
  2. Dopo aver lavorato con questo notebook per un po ', vorrei fare alcuni calcoli scratch in un taccuino separato, con il suo contesto privato, avendo accesso alle definizioni che stavo usando nel notebook "principale". Poiché ho impostato il contesto privato, è necessario modificare manualmente $ ContextPath

Fare tutto questo a mano più e più volte è un dolore, quindi automatizziamo! Innanzitutto, alcuni codici di utilità:

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

Ora creiamo una macro che inserirà le seguenti celle nel notebook:

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

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

Ora quando scrivo MyPrivatize[] crea il contesto privato e carica il mio pacchetto standard. Ora creiamo un comando che aprirà un nuovo blocco appunti con il suo contesto privato (in modo che tu possa hackerare lì con selvaggio abbandono senza il rischio di rovinare le definizioni), ma abbia accesso ai tuoi contesti attuali.

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

La cosa interessante di questo è che a causa di SelfDestruct, quando il comando viene eseguito, non lascia traccia nel notebook corrente, il che è positivo, perché altrimenti creerebbe solo disordine.

Per ulteriori punti di stile, puoi creare trigger di parole chiave per queste macro utilizzando InputAutoReplacements, ma lascerò questo come esercizio per il lettore.


7

PutAppend con PageWidth -> Infinity

In Mathematica l' utilizzo del PutAppendcomando è il modo più semplice per mantenere un file di registro in esecuzione con risultati di calcoli intermedi. Ma utilizza per PageWith->78impostazione predefinita quando si esportano espressioni in un file e quindi non esiste alcuna garanzia che ogni output intermedio occupi solo una riga nel registro.

PutAppendnon ha alcuna opzione in sé, ma tracciare le sue valutazioni rivela che si basa sulla OpenAppendfunzione che ha l' PageWithopzione e consente di modificare il suo valore predefinito con il SetOptionscomando:

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

Quindi possiamo arrivare PutAppendad aggiungere solo una riga alla volta impostando:

SetOptions[OpenAppend, PageWidth -> Infinity]

AGGIORNARE

È stato introdotto un bug nella versione 10 (risolto nella versione 11.3): SetOptionsnon influenza più il comportamento di OpenWritee OpenAppend.

Una soluzione alternativa è implementare la propria versione di PutAppendcon l' PageWidth -> Infinityopzione esplicita :

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

Nota che possiamo anche implementarlo tramite WriteStringcome mostrato in questa risposta, ma in questo caso sarà necessario convertire in modo preliminare l'espressione nella corrispondente InputFormvia ToString[expr, InputForm].


6

Stavo guardando attraverso uno dei miei pacchetti per l'inclusione in questo, e ho trovato alcuni messaggi che ho definito che miracoli: Debug::<some name>. Per impostazione predefinita, sono disattivati, quindi non producono sovraccarico. Ma posso sporcare il mio codice con loro e attivarli se devo capire esattamente come si sta comportando un po 'di codice.


Da The Help> Dalla versione 2.0 (rilasciata nel 1991), Debug è stato sostituito da Trace.
Dr. belisarius,

1
@belisarius, hai perso il punto. Non è né le funzioni DebugTrace; è un insieme di messaggi che ho creato con cui posso sporcare il mio codice per attivarlo / disattivarlo a piacimento. Sono preceduti dalla parola Debug, nello stesso modo in cui un usagemessaggio è preceduto dal nome della funzione. Fornisce la stessa funzionalità di mettere un mucchio di coutistruzioni nel codice c ++.
rcollyer,

1
Oh scusami. Mi sono confuso perché non mi sono mai laureato all'asilo per non aver imparato "I capitali sono per i paesi": D
Dr. belisarius,

6

Una delle cose che mi preoccupa dei costrutti di scoping integrati è che valutano tutte le definizioni delle variabili locali contemporaneamente, quindi non puoi scrivere per esempio

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

Qualche tempo fa ho inventato una macro chiamata WithNest che ti consente di farlo. Lo trovo utile, dal momento che ti consente di mantenere le associazioni delle variabili locali senza dover fare qualcosa di simile

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

Alla fine, il modo migliore che ho trovato per farlo è stato usando un simbolo speciale per rendere più semplice la ricognizione sull'elenco dei binding e ho inserito la definizione nel suo pacchetto per mantenere nascosto questo simbolo. Forse qualcuno ha una soluzione più semplice a questo problema?

Se vuoi provarlo, inserisci quanto segue in un file chiamato 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 ha registrato una versione di questo, e fa riferimento alla tua domanda sul gruppo matematico: stackoverflow.com/questions/4190845/custom-notation-question/...
Mr.Wizard

Grazie per la segnalazione! È da un po 'che non guardo queste cose, ed è interessante vedere tutti questi altri approcci.
DGrady,

5

Questo è stato scritto da Alberto Di Lullo, (che non sembra essere in Stack Overflow).

CopyToClipboard, per Mathematica 7 (in Mathematica 8 è integrato)

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

Post originale: http://forums.wolfram.com/mathgroup/archive/2010/Jun/msg00148.html

Ho trovato questa routine utile per copiare negli Appunti grandi numeri reali in forma decimale ordinaria. Per esempioCopyToClipboard["123456789.12345"]

Cell[OutputFormData@expr] rimuove ordinatamente le virgolette.


5

Questo codice crea una tavolozza che carica la selezione su Stack Exchange come immagine. Su Windows, viene fornito un pulsante aggiuntivo che fornisce un rendering più fedele della selezione.

Copia il codice in una cella del notebook e valuta. Quindi estrarre la tavolozza dall'output e installarla utilizzandoPalettes -> Install Palette...

In caso di problemi, pubblica un commento qui. Scarica la versione per notebook qui .


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

Sono sicuro che molte persone hanno incontrato la situazione in cui eseguono alcune cose, rendendosi conto che non solo ha bloccato il programma, ma non hanno nemmeno salvato negli ultimi 10 minuti!

MODIFICARE

Dopo aver sofferto di questo per un po 'di tempo, un giorno ho scoperto che si può creare il salvataggio automatico all'interno del codice Mathematica . Penso che l'utilizzo di tale salvataggio automatico mi abbia aiutato molto in passato e ho sempre pensato che la possibilità stessa fosse qualcosa che non molte persone sono consapevoli di poter fare.

Il codice originale che ho usato è in fondo. Grazie ai commenti ho scoperto che è problematico e che è molto meglio farlo in modo alternativo, usando ScheduledTask(che funzionerà solo in Mathematica 8).

Il codice per questo può essere trovato in questa risposta da Sjoerd C. de Vries (Dal momento che non sono sicuro se va bene copiarlo qui, lo lascio solo come link.)


La soluzione seguente sta usando Dynamic. Salverà il notebook ogni 60 secondi, ma apparentemente solo se la sua cella è visibile . Lo lascio qui solo per motivi di completamento. (e per gli utenti di Mathematica 6 e 7)

/MODIFICARE

Per risolverlo uso questo codice all'inizio di un notebook:

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

Ciò salverà il tuo lavoro ogni 60 secondi.
Lo preferisco NotebookAutoSave[]perché salva prima che l'input venga elaborato e perché alcuni file sono più di testo che di input.

Inizialmente l'ho trovato qui: http://en.wikipedia.org/wiki/Talk:Mathematica#Criticisms

Si noti che una volta eseguita questa riga, il salvataggio avverrà anche se si chiude e si riapre il file (purché l'aggiornamento dinamico sia abilitato).

Inoltre, poiché non esiste alcun annullamento in Mathematica , fai attenzione a non eliminare tutti i tuoi contenuti, poiché il salvataggio lo renderà irreversibile (per precauzione, rimuovo questo codice da ogni blocco appunti finito)


potresti anche salvarlo con un nome diverso (ad es. aggiungendo l'ora e la data attuali alla fine del nome file) e magari in una directory specifica ("Backup", diciamo). questo sarebbe come una forma primitiva di versioning.
acl

Puoi fare qualcosa del genere NotebookSave[SelectedNotebook[], "work-" <> IntegerString[i] <> ".nb"]; i++, ma penso che qualsiasi tipo di riferimento all'attuale nome del notebook diventerà ricorsivo.
tsvikas,

2
Ho pensato che gli Dynamicoggetti si aggiornassero solo quando sono visibili, quindi non sarei sicuro che questo metodo funzionerebbe se, ad esempio, fai scorrere l' Dynamicoggetto fuori dall'area visibile. Poi di nuovo, non ho provato. In ogni caso, l'ho semplicemente offerto come suggerimento.
acl

1
Puoi testarlo usando Dynamic[Refresh[i++, UpdateInterval -> 1, TrackedSymbols -> {}]]. Scorri il numero crescente dalla vista, attendi un minuto, scorri indietro e vedi che il numero non viene incrementato di 60. Informazioni UpdateInterval: questo è di solito usato se possibile, ma se il tuo codice include variabili che cambiano, questa modifica attiva un nuovo aggiornamento prima del l'intervallo termina. Prova la riga precedente senzaTrackedSymbols
Sjoerd C. de Vries,

1
@ j0ker5 Prova il mio codice sopra e puoi vedere che UpdateInterval non forza sempre la spaziatura degli aggiornamenti con l'intervallo specificato. Questo codice mostra anche che Dynamic funziona solo se la cella in cui è contenuta è visibile nel frontend . Si ferma davvero nel momento in cui è fuori dalla vista. Le persone non dovrebbero davvero fidarsi di questo codice per salvare i propri file perché non lo fanno. È pericoloso
Sjoerd C. de Vries,


3

Lo trovo davvero utile durante lo sviluppo di pacchetti per aggiungere questa scorciatoia da tastiera al mio SystemFiles/FrontEnd/TextResources/Windows/KeyEventTranslations.trfile.

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

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

Successivamente per ogni Packagename.mho PackagenameTest.nbcreato un notebook per i test e le prime 2 celle del notebook di test sono impostate come celle di inizializzazione. Nella prima cella ho messo

Needs["PackageManipulations`"]

per caricare l'utilissima libreria PackageManipulations che è stata scritta da Leonid. La seconda cella contiene

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

che tutti eseguono il ricaricamento effettivo del pacchetto. Nota che le prime due righe sono presenti solo per Removetutti i simboli, poiché mi piace mantenere i contesti il ​​più possibile puliti.

Quindi il flusso di lavoro per scrivere e testare un pacchetto diventa qualcosa del genere.

  1. Salva le modifiche in Packagename.m.
  2. Vai PackagenameTest.nbe fai CTRL + ALT + i.

Questo fa sì che le celle di inizializzazione ricarichino il pacchetto, il che rende il test davvero semplice.


1

La seguente funzione format[expr_]può essere utilizzata per indentare / formattare mathematicaespressioni non formattate che si estendono su una pagina

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

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


Per cosa stai usando questo in pratica? L'output è un po 'troppo "divertente" per essere leggibile quando applicato al codice o ai dati (elenchi, format@RandomInteger[10,{3,3}]): pastebin.com/nUT54Emq Dato che hai già le basi e sei interessato a questo, puoi migliorare il codice per produrre una formattazione leggibile in modo utile? Quindi il prossimo passo sarebbe quello di creare un pulsante incolla che creerà una cella di input con codice Mathematica ben rientrato (preferibilmente preservando i commenti !!) Vedi anche la mia domanda correlata .
Szabolcs,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.