O que há na sua mala de ferramentas do Mathematica? [fechadas]


152

Todos sabemos que o Mathematica é ótimo, mas também frequentemente não possui funcionalidade crítica. Que tipo de pacotes / ferramentas / recursos externos você usa com o Mathematica?

Editarei (e convido outras pessoas a fazê-lo também) este post principal para incluir recursos focados na aplicabilidade geral da pesquisa científica e que o maior número possível de pessoas achará útil. Sinta-se à vontade para contribuir com qualquer coisa, até pequenos trechos de código (como fiz abaixo para uma rotina de tempo).

Além disso, recursos não documentados e úteis no Mathematica 7 e além de você se encontrou, ou desenterrados de algum artigo / site, são bem-vindos.

Inclua uma breve descrição ou comentário sobre por que algo é ótimo ou qual utilitário ele fornece. Se você criar um link para livros na Amazon com links afiliados, mencione-o, por exemplo, colocando seu nome após o link.


Pacotes:

  1. LevelSchemeé um pacote que expande bastante a capacidade do Mathematica de produzir gráficos de boa aparência. Eu o uso se não for para qualquer outra coisa, então para o controle muito melhorado sobre os carrapatos dos quadros / eixos. Sua versão mais recente é chamada SciDraw, e será lançada ainda este ano.
  2. David Park's Presentation Package(US $ 50 - sem taxa para atualizações)
  3. O grassmannOpspacote de Jeremy Michelson fornece recursos para fazer álgebra e cálculo com variáveis ​​e operadores de Grassmann que têm relações de comutação não triviais.
  4. GrassmannAlgebraPacote e livro de John Brown para trabalhar com as álgebras de Grassmann e Clifford.
  5. O RISC (Instituto de Pesquisa para Computação Simbólica) tem uma variedade de pacotes para o Mathematica (e outros idiomas) disponíveis para download. Em particular, existe o Theorema para a prova automatizada de teoremas e a infinidade de pacotes para soma simbólica, equações de diferença etc. na página de software do grupo Algorithmic Combinatorics .

Ferramentas:

  1. MASHé o excelente script Perl de Daniel Reeves, essencialmente fornecendo suporte a scripts para o Mathematica v7. (Agora incorporado no Mathematica 8 com a -scriptopção.)
  2. Um alternate Mathematica shellcom uma entrada de linha de leitura GNU (usando python, * nix apenas)
  3. O pacote ColourMaths permite selecionar visualmente partes de uma expressão e manipulá-las. http://www.dbaileyconsultancy.co.uk/colour_maths/colour_maths.html

Recursos:

  1. O próprio repositório da Wolfram possui MathSourcemuitos notebooks úteis e estreitos para várias aplicações. Verifique também as outras seções, como

  2. O Wikilivro Mathematica .

Livros:

  1. Programação do Mathematica: uma introdução avançada de Leonid Shifrin ( web, pdf) é uma leitura obrigatória se você quiser fazer algo mais do que loops For no Mathematica. Temos o prazer de Leonidresponder ele mesmo aqui.
  2. Métodos quânticos com o Mathematica por James F. Feagin ( amazon )
  3. O Livro Mathematica de Stephen Wolfram ( amazônia ) ( web)
  4. Esboço de Schaum ( amazônia )
  5. Mathematica in Action de Stan Wagon ( amazon ) - 600 páginas de exemplos legais e vão para o Mathematica versão 7. As técnicas de visualização são especialmente boas, você pode ver algumas delas no autor Demonstrations Page.
  6. Fundamentos de programação do Mathematica por Richard Gaylord ( pdf) - Uma boa introdução concisa para a maioria do que você precisa saber sobre a programação do Mathematica.
  7. Livro de receitas do Mathematica de Sal Mangano publicado por O'Reilly 2010 832 páginas. - Escrito no conhecido estilo O'Reilly Cookbook: Problema - Solução. Para intermediários.
  8. Equações Diferenciais com Mathematica, 3ª Ed. Elsevier 2004 Amsterdam por Martha L. Abell, James P. Braselton - 893 páginas Para iniciantes, aprenda a resolver DEs e Mathematica ao mesmo tempo.

Recursos não documentados (ou pouco documentados):

  1. Como personalizar os atalhos de teclado do Mathematica. Veja this question.
  2. Como inspecionar padrões e funções usadas pelas próprias funções do Mathematica. Vejothis answer
  3. Como obter tamanho consistente para GraphPlots no Mathematica? Veja this question.
  4. Como produzir documentos e apresentações com o Mathematica. Veja this question.

2
O Mathematica 8 está disponível com uma integração muito melhor de scripts de shell. wolfram.com/mathematica/new-in-8/mathematica-shell-scripts
Joshua Martell

2
+1, para LevelScheme. Às vezes é um pouco lento. Porém, ele tem um método sensato para criar marcas de escala e é muito mais fácil criar layouts de diário dignos de gráficos Grid, ou qualquer coisa assim.
Rclyly

2
Conforme proposto por Alexey nos comentários sobre essa pergunta stackoverflow.com/questions/5152551/… , propus a renomeação de marca para o Mathematica aqui: meta.stackexchange.com/questions/81152/… . Por favor, dê uma olhada e vote se você concorda. Eu publico aqui porque esta pergunta tem muitos favoritos na comunidade Mma aqui.
perfil completo de belisarius

1
Tudo, essa pergunta realmente deve ser um wiki da comunidade por todos os motivos usuais: não tem resposta correta e é mais uma lista do que qualquer outra coisa. Peço desculpas a todos os que lucraram bastante com essa questão.
precisa saber é o seguinte

2
Essas respostas a esta pergunta são construtivas, devem ser reabertas.
MR

Respostas:


29

Já mencionei isso antes, mas a ferramenta que acho mais útil é uma aplicação Reape Sowque imita / estende o comportamento de GatherBy:

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

Isso me permite agrupar listas por qualquer critério e transformá-las no processo. A maneira como funciona é que uma função de critério ( f) marca cada item da lista, cada item é transformado por uma segunda função fornecida ( g) e a saída específica é controlada por uma terceira função ( h). A função haceita dois argumentos: uma marca e uma lista dos itens coletados que possuem essa marca. Os itens mantêm sua ordem original; portanto, se você definir h = #1&, receberá uma ordem não ordenada Union, como nos exemplos de Reap. Mas, pode ser usado para processamento secundário.

Como exemplo de sua utilidade, tenho trabalhado com o Wannier90, que gera o Hamiltoniano espacialmente dependente em um arquivo em que cada linha é um elemento diferente na matriz, como segue

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

Para transformar essa lista em um conjunto de matrizes, reuni todas as sublistas que contêm a mesma coordenada, transformei as informações do elemento em uma regra (por exemplo, {i, j} -> Re [Hij] + I Im [Hij]) e em seguida, transformou as regras coletadas em um SparseArraytudo com o único liner:

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

Honestamente, este é o meu canivete suíço, e torna as coisas complexas muito simples. A maioria das minhas outras ferramentas é um pouco específica do domínio, então provavelmente não as publicarei. No entanto, a maioria, se não todos, faz referência SelectEquivalents.

Editar : não imita completamente, GatherBypois não pode agrupar vários níveis da expressão da maneira mais simples GatherBypossível. No entanto, Mapfunciona muito bem para a maioria do que eu preciso.

Exemplo : @Yaroslav Bulatov pediu um exemplo independente. Aqui está uma das minhas pesquisas que foi bastante simplificada. Então, digamos que temos um conjunto de pontos em um 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}}

e gostaríamos de reduzir o número de pontos por um conjunto de operações de simetria. (Para os curiosos, estamos gerando o pequeno grupo de cada ponto.) Neste exemplo, vamos usar um eixo de rotação de quatro vezes ao redor do eixo z

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

Usando SelectEquivalents, podemos agrupar os pontos que produzem o mesmo conjunto de imagens nessas operações, ou seja, são equivalentes, usando o seguinte

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 produz 3 sublistas contendo os pontos equivalentes. (Observe que Unioné absolutamente vital aqui, pois garante que a mesma imagem seja produzida por cada ponto. Originalmente, eu usei Sort, mas se um ponto está em um eixo de simetria, é invariante sob a rotação sobre esse eixo, fornecendo uma imagem extra de si mesmo. Portanto, Unionelimina essas imagens extras. Além disso, GatherByproduziria o mesmo resultado.) Nesse caso, os pontos já estão em uma forma que eu usarei, mas eu só preciso de um ponto representativo de cada agrupamento e gostaria de uma contagem dos pontos equivalentes. Desde que eu não preciso transformar cada ponto, eu uso oIdentityfunção na segunda posição. Para a terceira função, precisamos ter cuidado. O primeiro argumento passado a ele serão as imagens dos pontos sob as rotações que, para o ponto, {0,0,0}são uma lista de quatro elementos idênticos, e usá-lo eliminaria a contagem. No entanto, o segundo argumento é apenas uma lista de todos os elementos que possuem essa tag, portanto, ela conterá apenas {0,0,0}. Em código,

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

Observe que este último passo pode ser realizado com a mesma facilidade

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

Porém, é fácil com este e o exemplo menos completo acima ver como transformações muito complexas são possíveis com um mínimo de código.


O código Fortran77 original foi reestruturado no Dia de Ação de Graças de 1996 e, portanto, por muitos anos conhecido como turkey.f ...: D Gráficos muito bons, BTW. Lembrei-me do Falicov monstro ...
Dr. belisarius

@belisarius, eu não tinha lido a história, isso é engraçado. Acabei de começar a usar o Wannier90, mas é um dos melhores Fortrancódigos organizados e bem escritos que já vi. Faz-me quase considerar o uso de Fortran... #
1811 rcollyer

Gostaria de saber se você poderia adicionar um exemplo independente de SelectEquivalents em ação
Yaroslav Bulatov

@Yaroslav Bulatov, adicionou um exemplo, por solicitação. Avise-me se isso ajudar. Caso contrário, veremos o que podemos fazer.
rcollyer

Você recebe a marca de seleção desta "pergunta" para obter a contribuição mais interessante do snippet de código.
Timo

57

Uma das coisas boas da interface do notebook Mathematica é que ele pode avaliar expressões em qualquer idioma, não apenas no Mathematica. Como um exemplo simples, considere criar um novo tipo de célula de entrada do Shell que transmita a expressão contida no shell do sistema operacional para avaliação.

Primeiro, defina uma função que delegue a avaliação de um comando textual ao shell externo:

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

O segundo argumento é necessário e ignorado por razões que se tornarão aparentes mais tarde. Em seguida, queremos criar um novo estilo chamado Shell :

  1. Abra um novo notebook.
  2. Selecione o item de menu Formatar / Editar folha de estilo ...
  3. Na caixa de diálogo, ao lado de Digite um nome de estilo: digite Shell.
  4. Selecione o suporte de célula ao lado do novo estilo.
  5. Selecione o item de menu Cell / Show Expression
  6. Substitua a expressão da célula pelo Texto da Etapa 6 fornecido abaixo.
  7. Mais uma vez, selecione o item de menu Cell / Show Expression
  8. Feche a caixa de diálogo.

Use a seguinte expressão de célula como o Texto da Etapa 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"]

A maior parte dessa expressão foi copiada diretamente do estilo interno do programa . As principais mudanças são estas linhas:

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

Evaluatablehabilita a funcionalidade SHIFT + ENTER para a célula. A avaliação chamará a CellEvaluationFunctionaprovação do conteúdo da célula e do tipo de conteúdo como argumentos ( shellEvaluateignora o último argumento). CellFrameLabelsé apenas uma delicadeza que permite ao usuário identificar que essa célula é incomum.

Com tudo isso no lugar, agora podemos inserir e avaliar uma expressão de shell:

  1. No bloco de notas criado nas etapas acima, crie uma célula vazia e selecione o suporte da célula.
  2. Selecione o item de menu Formato / Estilo / Shell .
  3. Digite um comando válido do shell do sistema operacional na célula (por exemplo, 'ls' no Unix ou 'dir' no Windows).
  4. Pressione SHIFT + ENTER.

É melhor manter esse estilo definido em uma folha de estilo localizada centralmente. Além disso, funções de avaliação como shellEvaluatesão melhor definidas como stubs usando DeclarePackage no init.m. Os detalhes de ambas as atividades estão além do escopo desta resposta.

Com essa funcionalidade, é possível criar blocos de anotações que contêm expressões de entrada em qualquer sintaxe de interesse. A função de avaliação pode ser escrita no Mathematica puro ou delegar uma ou todas as partes da avaliação a uma agência externa. Esteja ciente de que existem outros ganchos relacionados à avaliação de células, como CellEpilog, CellProloge CellDynamicExpression.

Um padrão comum envolve gravar o texto da expressão de entrada em um arquivo temporário, compilar o arquivo em algum idioma, executar o programa e capturar a saída para a exibição final na célula de saída. Há muitos detalhes a serem abordados ao implementar uma solução completa desse tipo (como capturar mensagens de erro corretamente), mas é preciso apreciar o fato de que não é apenas possível fazer coisas como essa, mas também praticar.

Em uma nota pessoal, são características como essa que fazem do notebook a interface do centro do meu universo de programação.

Atualizar

A seguinte função auxiliar é útil para criar essas células:

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

É usado assim:

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

Agora, se shellCell[]for avaliada, a célula de entrada será excluída e substituída por uma nova célula de entrada que avalia seu conteúdo como um comando de shell.


3
@WReach +100! Eu gostaria de saber isso antes! Isso é muito útil, pelo menos para mim. Obrigado por compartilhar!
Leonid Shifrin 27/03

Isso parece bastante instável! CellEvaluationFunctiontambém poderia ser usado para hackers de baixo nível de sintaxe.
Mr.Wizard

@ Leonid Pelo menos para o FrontEnd, é CellEvaluationFunctiono gancho que você estava procurando?
Mr.Wizard

2
Além disso: existe outra Cellopção relacionada à avaliação celular - Evaluator -> "EvaluatorName". O significado de "EvaluatorName"pode ser configurado através da caixa de diálogo Evaluation :: Kernel Configuration Options .... Ainda não sei se é possível configurá-lo programaticamente ... Essa técnica permite usar MathKernels diferentes Cellem s diferentes em um Notebook. Esses MathKernels podem ser de diferentes versões do Mathematica instaladas.
Alexey Popkov #

1
@Szabolcs Todos os meus próprios usos dessa técnica envolvem uma abordagem stdin _ / _ stdout , como ilustrado acima, ou uma solicitação remota independente, como uma consulta SQL ou uma operação HTTP. Você pode tentar configurar um aplicativo da web Python REPL (como este ) e interagir com ele usando Import, ou talvez iniciar um processo externo do Python e se comunicar através de seus fluxos (por exemplo, usando um Java ProcessBuilder ). Estou certo que há uma maneira melhor Mathematica - soa como uma pergunta boa SO :)
WReach

36

Todd Gayley (Wolfram Research) acabou de me enviar um belo truque que permite "quebrar" funções internas com código arbitrário. Sinto que tenho que compartilhar esse instrumento útil. A seguir está a resposta de Todd no meu question.

Um pouco de história interessante? O estilo de hack para "empacotar" uma função interna foi inventado por volta de 1994 por Robby Villegas e eu, ironicamente para a função Message, em um pacote chamado ErrorHelp que escrevi para o Mathematica Journal. naquela época. Tem sido usado muitas vezes, por muitas pessoas, desde então. É meio que um truque interno, mas acho justo dizer que se tornou a maneira canônica de injetar seu próprio código na definição de uma função interna. Faz o trabalho bem feito. Obviamente, você pode colocar a variável $ inMsg em qualquer contexto privado que desejar.

Unprotect[Message];

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

Protect[Message];

@ Alexey Eu tenho dificuldades para entender isso. Você poderia explicar como isso funciona? Não deveria haver uma [desproteger [mensagem] em algum lugar? E este exemplo não contém recursão infinita? E! TrueQ [$ inMsg] faz sentido com $ inMsg definido dentro do escopo do bloco e indefinido fora do bloco?
Sjoerd C. de Vries

9
@ Sjoerd Pelo que entendi, o de Unprotectfato tem que ser, foi deixado de fora. O ponto de Block(escopo dinâmico) e $inMsgé exatamente para impedir a recursão infinita. Como $inMsgé indefinido do lado de fora (esse é um requisito importante), inicialmente TrueQavalia como Falsee entramos no corpo da função. Mas quando temos a chamada de função dentro do corpo, a condição é avaliada como False(uma vez que a variável foi redefinida pelo bloco). Portanto, a regra definida pelo usuário não corresponde e a regra interna é usada.
Leonid Shifrin

1
@ Leonid Obrigado, eu entendi agora. Muito esperto!
Sjoerd C. de Vries

1
Acabei de descobrir que essa técnica foi discutida por Robby Villegas, da Wolfram Research, na 1999 Developer Conference. Consulte o bloco de notas "Trabalhando com expressões não avaliadas" publicado aqui . Neste caderno, Robby Villegas discute esse truque na subseção "Meu bloco para capturar chamadas para funções internas".
Alexey Popkov 31/03

1
@ Mr.Wizard Esta não é a única maneira de fazer isso. Por um longo tempo, usei uma versão em que você redefine o DownValuestempo de execução. Você pode ver esta postagem groups.google.com/group/comp.soft-sys.math.mathematica/… , por exemplo ( SetDelayedredefinição) . Mas meu método é menos elegante, menos robusto, mais suscetível a erros e torna a quebra da recursão muito menos trivial para implementar. Portanto, na maioria das situações, o método descrito por @Alexey vence.
precisa saber é o seguinte

25

Este não é um recurso completo, portanto, eu o jogo aqui na seção de respostas, mas achei muito útil ao descobrir problemas de velocidade (o que, infelizmente, é uma grande parte do que é a programação do 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};

O uso é então simplesmente timeAvg@funcYouWantToTest.

EDIT: Mr. Assistente forneceu uma versão mais simples que elimina Throwe Catche é um pouco mais fácil de analisar:

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

EDIT: Aqui está uma versão do acl (retirada daqui ):

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]

Feito de novo e de novo ... hora de entrar na minha própria bolsa. tnx!
Dr. belisarius

1
Um problema com esse código (bem, pode ser que esse seja o ponto de vista de um perfeccionista) é que podemos pegar algo que não lançamos e interpretá-lo como um resultado de tempo incorreto. Ambos Catche Throwdeveriam ter sido usados ​​com tags de exceção exclusivas.
Leonid Shifrin

2
Timo, fico feliz que você goste da minha versão o suficiente para incluí-la. Obrigado por me dar crédito também. Estou curioso sobre a maneira como você reformatou meu código. Não sigo nenhuma orientação específica em meu próprio código, além de facilitar a leitura; existe uma escola de pensamento por trás de sua reformatação, ou é apenas preferência? O Mathematica não incentiva a formatação precisa do código devido à maneira como reflete a entrada, mas a publicação do código aqui está me fazendo começar a pensar sobre isso. BTW, acho que você quer dizer " Throwe Catch" em vez de " Reape Sow".
Mr.Wizard

1
@ Simon, Sr. Wizard, eu uso esse método para cronometrar versões diferentes de funções pequenas, que serão chamadas muitas vezes. Não necessariamente em uma estrutura de loop, mas certamente dentro de construções que o MMA otimiza. Nesse contexto, a execução de um loop faz sentido e o desempenho será próximo ao aplicativo da vida real. Para cronometrar grandes funções complexas (talvez até células inteiras de inicialização), o método de Simon fornecerá um resultado melhor. Apesar de tudo, estou mais interessado em valores relativos e qualquer um dos métodos deve funcionar lá.
Timo

3
Agora há RepeatedTimingpara fazer isso.
Masterxilo # 9/16

20

Internal`InheritedBlock

Eu aprendi recentemente a existência de uma função útil que Internal`InheritedBlock, a partir desta mensagem de Daniel Lichtblau, no grupo de notícias oficial.

Pelo que entendi, Internal`InheritedBlockpermite passar uma cópia de uma função de saída dentro do Blockescopo:

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]

Eu acho que essa função pode ser muito útil para todos que precisam modificar temporariamente as funções internas!

Comparação com bloco

Vamos definir alguma função:

a := Print[b]

Agora queremos passar uma cópia desta função para o Blockescopo. O julgamento ingênuo não dá o que queremos:

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

During evaluation of In[9]:= b

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

Agora, tentando usar a definição atrasada no primeiro argumento de Block(também é um recurso não documentado):

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

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

During evaluation of In[3]:= b

Vemos que, nesse caso, afunciona, mas não temos uma cópia do original adentro do Blockescopo.

Agora vamos tentar Internal`InheritedBlock:

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

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

Temos uma cópia da definição original adentro do Blockescopo e podemos modificá-la da maneira que queremos, sem afetar a definição global para a!


+1 Muito útil! Mais uma ferramenta na mochila e 10 pontos mais perto do privilégio Editar para você.
precisa saber é o seguinte

Para mim, isso aparece como uma variante da avaliação precoce ou tardia ou não e completa.
user2432923

19

O Mathematica é uma ferramenta afiada, mas pode reduzir o seu comportamento um pouco digitado e avalanches de mensagens de diagnóstico enigmáticas . Uma maneira de lidar com isso é definir funções seguindo este idioma:

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

Isso é muito clichê, que muitas vezes sou tentado a ignorar. Especialmente na criação de protótipos, o que acontece muito no Mathematica. Então, eu uso uma macro chamada defineque me permite ficar disciplinado, com muito menos clichê.

Um uso básico de defineé assim:

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

fact[5]

120

Não parece muito a princípio, mas existem alguns benefícios ocultos. O primeiro serviço que definefornece é que ele se aplica automaticamente ClearAllao símbolo que está sendo definido. Isso garante que não haja definições restantes - uma ocorrência comum durante o desenvolvimento inicial de uma função.

O segundo serviço é que a função que está sendo definida é automaticamente "fechada". Com isso, quero dizer que a função emitirá uma mensagem e abortará se for invocada com uma lista de argumentos que não corresponde a uma das definições:

fact[-1]

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

Esse é o valor principal de define, que captura uma classe de erro muito comum.

Outra conveniência é uma maneira concisa de especificar atributos na função que está sendo definida. Vamos fazer a função Listable:

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

fact[{3, 5, 8}]

{6, 120, 40320}

Além de todos os atributos normais, defineaceita um atributo adicional chamado Open. Isso evita defineadicionar a definição de erro geral à função:

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

successor /@ {1, "hi"}

{2, successor["hi"]}

Vários atributos podem ser definidos para uma função:

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

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

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

Sem mais delongas, aqui está a definição 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: ``";

A implementação exibida não suporta valores superiores nem currying, nem padrões mais gerais que a simples definição de função. Continua sendo útil, no entanto.


2
+1 - isso é realmente útil. Eu tenho usado ferramentas semelhantes. Macros (assim como introspecção e outras técnicas de metaprogramação) podem ser muito poderosas, mas parecem ser subestimadas geralmente na comunidade Mathematica, ou pelo menos essa tem sido minha impressão até agora.
precisa saber é o seguinte

Acabei de definir algo semelhante. +1 no suporte ao CompoundExpression para executar várias definições, abortar [] (parece melhor que mais mensagens) e aberto (agradável para, por exemplo, construtores).
Masterxilo 18/08/16

16

Comece sem um notebook em branco aberto

Fiquei incomodado com o Mathematica começar com um caderno em branco aberto. Eu poderia fechar este caderno com um script, mas ele ainda seria aberto brevemente. Meu truque é criar um arquivo Invisible.nbcontendo:

Notebook[{},Visible->False]

E adicione isso ao meu Kernel\init.m:

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

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

Agora inicio o Mathematica abrindo Invisible.nb

Pode haver uma maneira melhor, mas isso me serviu bem.


Personalizado FoldeFoldList

Fold[f, x] é equivalente a Fold[f, First@x, Rest@x]

Aliás, acredito que isso pode chegar a uma versão futura do Mathematica.

Surpresa! Isso foi implementado, embora atualmente não esteja documentado. Fui informado de que foi implementado em 2011 por Oliver Ruebenkoenig, aparentemente pouco depois de eu ter postado isso. Obrigado 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]

Atualizado para permitir isso:

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

"Partição dinâmica"

Consulte a publicação no 7512 do Mathematica.SE para obter uma nova versão desta função.

Freqüentemente, quero particionar uma lista de acordo com uma sequência de comprimentos.

exemplo de pseudo-código:

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

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

Eu vim com isso:

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

Que então completei com isso, incluindo teste de argumento:

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

O terceiro argumento controla o que acontece com os elementos além da especificação de divisão.


Os truques do Mathematica de Szabolcs

O que eu uso com mais frequência é a paleta Colar dados tabulares

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

Modifique dados externos de dentro Compile

Recentemente, Daniel Lichtblau mostrou esse método que eu nunca tinha visto antes. Na minha opinião, estende significativamente a utilidade 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 Uma boa coleção! Com relação às modificações externas de dentro Compile- todo o meu post aqui: stackoverflow.com/questions/5246330/… , era mostrar essa possibilidade em uma configuração não trivial (havia uma solução mais rápida e mais rápida para o problema em questão postado lá) . Na IMO, a maior vitória aqui é a capacidade de emular passagem por referência e dividir grandes funções compiladas em blocos mais gerenciáveis ​​e reutilizáveis.
precisa

1
Você também pode ajustar as informações de sintaxe de Fold e FoldList em sua nova definição: SyntaxInformation [Fold] = {"ArgumentsPattern" -> {_ ,. , _}}; SyntaxInformation [FoldList] = {"ArgumentsPattern" -> {_, _., {_ }}};
Fayou

14

Problemas e soluções gerais de exportação de PDF / EMF

1) É completamente inesperado e não documentado, mas o Mathematica exporta e salva gráficos nos formatos PDF e EPS usando um conjunto de definições de estilo diferentes do utilizado para exibir os Notebooks na tela. Por padrão, os notebooks são exibidos na tela no ambiente de estilo "Trabalho" (que é o valor padrão da opção ScreenStyleEvironmentglobal $FrontEnd), mas são impressos no "Printout"ambiente de estilo (que é o valor padrão da opção PrintingStyleEnvironmentglobal $FrontEnd). Quando se exporta gráficos em formatos rasterizados, como GIF e PNG ou no formato EMF, o Mathematica gera gráficos que se parecem exatamente com os do Notebook. Parece que o"Working"ambiente de estilo é usado para renderização neste caso. Mas não é o caso quando você exporta / salva qualquer coisa nos formatos PDF ou EPS! Nesse caso, o "Printout"ambiente de estilo é usado por padrão, que difere muito do ambiente de estilo "Trabalhando". Primeiro de tudo, o "Printout"ambiente de estilo é definido Magnificationcomo 80% . Em segundo lugar, ele usa seus próprios valores para os tamanhos de fonte de diferentes estilos e isso resulta em alterações inconsistentes no tamanho do arquivo PDF gerado em comparação com a representação original na tela. O último pode ser chamado de flutuações do FontSize, que são muito irritantes. Felizmente, isso pode ser evitado configurando a opção PrintingStyleEnvironmentglobal $FrontEndcomo "Trabalhando" :

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

2) O problema comum com a exportação para o formato EMF é que a maioria dos programas (não apenas o Mathematica ) gera um arquivo com uma aparência agradável no tamanho padrão, mas que se torna feio quando você o amplia. Isso ocorre porque os metarquivos são amostrados com a fidelidade da resolução da tela . A qualidade do arquivo EMF gerado pode ser aprimorada Magnifyinserindo o objeto gráfico original, para que a exatidão da amostragem dos gráficos originais se torne muito mais precisa. Compare dois arquivos:

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 você inserir esses arquivos no Microsoft Word e ampliá-los, verá que o primeiro "a" tem serra enquanto o segundo não (testado com o Mathematica 6).

Outro caminho ImageResolutionsugerido por Chris Degnen (esta opção tem efeito pelo menos a partir do Mathematica 8):

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

3) No Mathematica , temos três maneiras de converter gráficos em metarquivo: via Exportpara "EMF"(maneira altamente recomendada: produz metarquivo com a mais alta qualidade possível), via Save selection As...item de menu ( produz um valor muito menos preciso , não recomendado) e via Edit ► Copy As ► Metafileitem de menu ( eu recomendo fortemente contra esta rota ).


13

Por demanda popular, o código para gerar os 10 principais respondedores de SO (exceto anotações ) usando a API SO .

insira a descrição da imagem aqui

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 postou uma pergunta pedindo quase esse código exato. Talvez seja mais apropriado lá, com um ou dois ajustes para se adequar à pergunta. Eu realmente valeria a pena rep, em oposição a esta questão.
precisa saber é o seguinte

@rcollyer está certo. Este é "Community Wiki"
Dr. belisarius

@belisarius Eu apenas copiou na resposta à pergunta de Brett ...
Sjoerd C. de Vries

@Sjoerd Seu lote aqui não é atualizado automaticamente.
perfil completo de belisarius

@belisarius Na verdade, eu estava esperando que você estava indo para tomar essa tarefa em cima de você ... ;-)
Sjoerd C. de Vries

13

Armazenando em cache expressões

Acho essas funções muito úteis para armazenar em cache qualquer expressão. O interessante aqui para essas duas funções é que a própria expressão retida é usada como uma chave do hashtable / symbol Cache ou CacheIndex, em comparação com a conhecida memorização no mathematica, na qual você só pode armazenar em cache o resultado se a função for definida como f [x_]: = f [x] = ... Para que você possa armazenar em cache qualquer parte de um código, isso é útil se uma função precisar ser chamada várias vezes, mas apenas algumas partes do código não devem ser recalculadas.

Armazenar em cache uma expressão independentemente de seus argumentos.

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

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

Na segunda vez que a expressão retorna 6 sem esperar.

Para armazenar em cache uma expressão usando uma expressão de alias que pode depender de um argumento da expressão em cache.

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

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

Se o expr levar algum tempo para calcular, é muito mais rápido avaliar {"f", 2} por exemplo, para recuperar o resultado em cache.

Para obter uma variação dessas funções para ter um cache localizado (por exemplo, a memória do cache é liberada automaticamente fora da construção do bloco), consulte este post. Evite chamadas repetidas para a Interpolação

Excluindo valores em cache

Para excluir valores em cache quando você não souber o número de definições de uma função. Considero que as definições têm um espaço em branco em algum lugar de seus argumentos.

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

Para excluir valores em cache quando você souber o número de definições de uma função (vai um pouco mais rápido).

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

Isso usa o fato de que as definições de uma função estão no final de sua lista DownValues, os valores em cache são anteriores.

Usando símbolos para armazenar dados e funções semelhantes a objetos

Também aqui estão funções interessantes para usar símbolos como objetos.

Já é sabido que você pode armazenar dados em símbolos e acessá-los rapidamente usando DownValues

mysymbol["property"]=2;

Você pode acessar a lista de chaves (ou propriedades) de um símbolo usando estas funções com base em quais itens enviados em uma postagem neste site:

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

Eu uso muito essa função para exibir todas as informações contidas nos DownValues ​​de um símbolo:

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

Finalmente, aqui está uma maneira simples de criar um símbolo que se comporta como um objeto na programação orientada a objetos (apenas reproduz o comportamento mais básico do OOP, mas acho a sintaxe 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
  ];

As propriedades são armazenadas como DownValues ​​e os métodos como Upvalues ​​atrasados ​​no símbolo criado pelo Módulo retornado. Encontrei a sintaxe da função2, que é a sintaxe OO usual para funções na estrutura de dados da Árvore no Mathematica .

Para obter uma lista dos tipos existentes de valores que cada símbolo possui, consulte http://reference.wolfram.com/mathematica/tutorial/PatternsAndTransformationRules.html e http://www.verbeia.com/mathematica/tips/HTMLLinks/Tricks_Misc_4.html .

Por exemplo, tente isso

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

Você pode ir além se quiser emular a herança de objetos usando um pacote chamado InheritRules disponível aqui http://library.wolfram.com/infocenter/MathSource/671/

Você também pode armazenar a definição da função não em newObject, mas em um símbolo de tipo, portanto, se NewObject retornou o tipo [newObject] em vez de newObject, você poderia definir a função e a função2 como essa fora do NewObject (e não dentro) e ter o mesmo uso de antes .

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

Use UpValues ​​[type] para ver se a função e a function2 estão definidas no símbolo de tipo.

Outras idéias sobre esta última sintaxe são apresentadas aqui https://mathematica.stackexchange.com/a/999/66 .

Versão aprimorada do SelectEquivalents

@rcollyer: Muito obrigado por trazer o SelectEquivalents à superfície, é uma função incrível. Aqui está uma versão aprimorada dos SelectEquivalents listados acima, com mais possibilidades e opções, o que facilita o uso.

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

Aqui estão exemplos de como esta versão pode ser usada:

Usando o Mathematica Gather / Collect corretamente

Como você faria uma função de tabela dinâmica no Mathematica?

Algoritmo de binning 2D rápido do Mathematica

Internal`Bag

Daniel Lichtblau descreve aqui uma estrutura de dados interna interessante para listas crescentes.

Implementando um Quadtree no Mathematica

Funções de depuração

Essas duas postagens apontam para funções úteis para depuração:

Como depurar ao escrever códigos pequenos ou grandes usando o Mathematica? bancada de trabalho? depurador de mma? ou alguma outra coisa? (Mostre)

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

Aqui está outra função baseada em Reap e Sow para extrair expressões de diferentes partes de um programa e armazená-las em um símbolo.

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

Aqui está um exemplo

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

Outros recursos

Aqui está uma lista de links interessantes para fins de aprendizado:

Uma coleção de recursos de aprendizado do Mathematica

Atualizado aqui: https://mathematica.stackexchange.com/a/259/66


Relacionado: " A melhor maneira de construir uma função com memória ". O WReach deu um exemplo incrível de função simples que não apenas lembra seus valores, mas também os grava em um arquivo e lê para trás ao reiniciar.
Alexey Popkov

1
Relacionado: " Mathematica: Como limpar o cache de um símbolo, ou seja, Desativar DownValues ​​sem padrão ". Esta pergunta mostra como limpar o cache usando a f[x_] := f[x] = some codememorização padrão .
Simon

7
+1 Há uma boa notação conveniente que elimina a necessidade de repetir o lado esquerdo da definição de uma função de armazenamento em cache, por exemplo: c:Cache[expr_] := c = expr.
Alcance 07/07

Variante agradável de SelectEquivalents. Eu acho que eu continuaria TagOnElementcomo o segundo parâmetro padrão Identity, pois é o mais usado deles. Também não acho que eu tenha incluído FinalOp, já que pode ser tratado lá dentro OpOnTaggedElems. Eu também reduzia os nomes das opções, já que o tamanho delas dificulta a digitação. Tente TagFunction, TransformElement, TransformResults, e TagPatternem vez disso. Ambos, TagPatterne MapLevelsão ótimas adições à funcionalidade e uma boa reescrita, em geral.
Rclyer

Obrigado pelo seu comentário rcollyer. Levei isso em consideração e melhorei também a legibilidade do código. Eu mantenho o FinalFunction porque ele opera com o resultado do Reap, por exemplo, se você deseja classificar seu resultado final por tags, se você os mantiver.
Fayou

12

Minhas funções de utilidade (eu tenho essas embutidas no MASH, mencionadas na pergunta):

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

Um truque que usei, que permite emular a maneira como a maioria das funções internas funciona com argumentos ruins (enviando uma mensagem e retornando todo o formulário sem avaliação), explora uma peculiaridade do caminho Condition funciona quando usado em uma definição. Se foodeve funcionar apenas com um argumento:

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

Se você tiver necessidades mais complexas, é fácil considerar a validação de argumentos e a geração de mensagens como uma função independente. Você pode fazer coisas mais elaboradas usando efeitos colaterais Conditionalém de apenas gerar mensagens, mas, na minha opinião, a maioria deles se enquadra na categoria "sleazy hack" e deve ser evitada, se possível.

Além disso, na categoria "metaprogramação", se você tiver um .marquivo Mathematica package ( ), poderá usar o "HeldExpressions"elemento para obter todas as expressões do arquivo agrupadas emHoldComplete . Isso torna o rastreamento de coisas muito mais fácil do que usar pesquisas baseadas em texto. Infelizmente, não há uma maneira fácil de fazer a mesma coisa com um notebook, mas você pode obter todas as expressões de entrada usando algo como o seguinte:

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

Por fim, você pode usar o fato de Moduleemular fechamentos lexicais para criar o equivalente aos tipos de referência. Aqui está uma pilha simples (que usa uma variação, o Conditiontruque para lidar com erros como um bônus):

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]

Agora você pode imprimir os elementos de uma lista em ordem inversa de uma maneira desnecessariamente complicada!

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

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

1
+1 para o HeldExpressionselemento em pacotes, não sabia disso. Normalmente, eu estava importando como string e depois usando ToExpressioncom HoldCompletecomo último argumento. Com relação ao uso Conditionde mensagens - essa é uma técnica padrão na criação de pacotes desde pelo menos 1994. Com relação à persistência por meio de Modulevars - eu tive um longo post sobre isso no Mathgroup há pouco tempo: groups.google.com/group/comp.soft- sys.math.mathematica /… (minha terceira postagem nesse segmento), está na mesma linha e possui links para alguns exemplos de uso não triviais.
Leonid Shifrin

@ Leonid Shifrin: Eu peguei a Conditioncoisa como tradição, provavelmente de um colega de trabalho, mas não percebi que era uma técnica padrão. O link sobre o uso de Modulesímbolos como tipos de referência é interessante!
Pillsy

+1, nunca pensei nisso. Quanto mais eu aprendo sobre esse idioma, mais poderoso ele parece.
Rclyly

@Pillsy, qual é o objetivo de fazer uma pilha dessa maneira?
Mr.Wizard

@ Mr.Wizard: Acabei de escolher uma das estruturas de dados mutáveis ​​mais simples que pude imaginar para ilustrar a técnica.
Pillsy

11

Definições de símbolo do sistema de impressão sem contexto anexado

A contextFreeDefinition[]função abaixo tentará imprimir a definição de um símbolo sem o contexto mais comum anexado. A definição pode ser copiada no Workbench e formatada para facilitar a leitura (selecione-a, clique com o botão direito do mouse em Source -> Format)

Clear[commonestContexts, contextFreeDefinition]

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

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

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

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

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

withRules []

Advertência: Esta função não localiza variáveis ​​da mesma maneira Withe o Modulefaz, o que significa que construções de localização aninhadas não funcionarão conforme o esperado. withRules[{a -> 1, b -> 2}, With[{a=3}, b_ :> b]] irá substituir ae bna aninhado Withe Rule, ao mesmo tempoWith não faz isso.

Essa é uma variante Withque usa regras em vez de =e :=:

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

Achei isso útil ao limpar o código escrito durante a experimentação e localizar variáveis. Ocasionalmente, acabo com listas de parâmetros na forma de {par1 -> 1.1, par2 -> 2.2}. Com os withRulesvalores dos parâmetros, é fácil injetar código previamente escrito usando variáveis ​​globais.

O uso é como With:

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

Antialiasing gráficos 3D

Essa é uma técnica muito simples para antialiasizar gráficos 3D, mesmo que seu hardware gráfico não o suporte nativamente.

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

Aqui está um exemplo:

Gráficos do Mathematica Gráficos do Mathematica

Observe que um valor grande nou um tamanho de imagem grande tende a expor os erros do driver gráfico ou a apresentar artefatos.


Funcionalidade diferencial do notebook

A funcionalidade diff do notebook está disponível no <<AuthorTools`pacote e (pelo menos na versão 8) no NotebookTools`contexto não documentado . Esta é uma pequena interface gráfica para diferenciar dois notebooks que estão abertos no momento:

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 do Mathematica


Tudo seria legal, mas isso realmente não localiza variáveis, como você pode ver atribuindo say a = 3; b = 4;antes da sua chamada de exemplo e depois chamando withRules. Você pode salvá-lo por vez usando o seguinte: SetAttributes[withRules, HoldAll];withRules[rules_, expr_] := Unevaluated[expr] /. Unevaluated[rules]. As diferenças semânticas da Withépoca: 1. os lados das regras agora não são avaliados 2. withRulesnão resolve os conflitos de nomenclatura com as construções de escopo interno, como o Withfaz. O último é bem sério - ser bom ou ruim, dependendo do caso.
precisa

@ Leonid Você está completamente certo, parece que eu nunca aprendo sobre como verificar o código corretamente antes de postar ... quando eu uso isso, eu praticamente nunca atribuo valores às variáveis, mas esse é um problema muito sério, você está certo. O que você acha da versão corrigida? (Eu realmente não me importo em não manipular Withs aninhados . Isso também nem sempre funciona com as construções de localização incorporadas, por exemplo With[{a=1}, Block[{a=2}, a]]. Você acha que há um bom motivo para o aninhado Blocknão localizar lá, como aninhado Withe Modulefaz?)
Szabolcs

@ Leonid, não usei simplesmente Unevaluated[rules]porque queria x -> 1+1avaliar o RHS.
Szabolcs

@ Leonid Você está realmente certo, o problema de localização aninhada pode ser bastante sério. Eu acho que Withs aninhados são fáceis de identificar e evitar, mas os padrões não são: With[{a = 1}, a_ -> a]localizam o interior aenquanto withRulesnão. Você sabe se existe alguma maneira de acessar o mecanismo de localização interno do Mathematica e criar novas construções (semelhantes a Rule) que também localizam? Provavelmente vou excluir esta resposta mais tarde, pois é mais perigoso do que útil, mas gostaria de brincar com ela um pouco mais antes.
Szabolcs

Eu acho que seu uso InheritedBlocké bem legal e resolve o problema com muita elegância. Quanto aos conflitos de escopo, normalmente as ligações para o escopo lexical ocorrem no "tempo de ligação lexical", que é - antes do tempo de execução, enquanto o escopo dinâmico é vinculado no tempo de execução, o que pode explicar isso. Você pode contrastar isso com o caso semelhante de Module, que permite um uso construtivo (veja, por exemplo, aqui stackoverflow.com/questions/7394113/… ). O problema é que Blockprecisa de algum símbolo para ...
Leonid Shifrin

9

Funções puras recursivas ( #0) parecem ser um dos cantos mais escuros do idioma. Aqui estão alguns exemplos não triviais de seu uso, nos quais isso é realmente útil (não que eles não possam ser feitos sem ele). A seguir, é uma função bastante concisa e razoavelmente rápida para encontrar componentes conectados em um gráfico, dada uma lista de arestas 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]];

O que acontece aqui é que primeiro mapeamos um símbolo fictício em cada um dos números de vértice e, em seguida, criamos uma maneira que, dado um par de vértices {f[5],f[10]}, digamos, f[5]avaliaria como f[10]. A função pura recursiva é usada como um compressor de caminho (para configurar a memorização de tal maneira que, em vez de longas cadeias f[1]=f[3],f[3]=f[4],f[4]=f[2], ..., os valores memorizados são corrigidos sempre que uma nova "raiz" do componente é descoberta, o que proporciona uma aceleração significativa. Como usamos a atribuição, precisamos que ela seja HoldAll, o que torna essa construção ainda mais obscura e mais atraente). Esta função é resultado de discussões on-line e off-line do Mathgroup envolvendo Fred Simons, Szabolcs Horvat, DrMajorBob e o seu verdadeiramente. Exemplo:

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 muito mais lento que um built-in, mas para o tamanho do código, bastante rápido ainda é IMO.

Outro exemplo: aqui está uma realização recursiva de Select, com base em listas vinculadas e funções puras recursivas:

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

Por exemplo,

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

No entanto, não é corretamente recursivo da cauda e irá explodir a pilha (travar o kernel) para listas maiores. Aqui está a versão recursiva da cauda:

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 exemplo,

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

A função para componentes conectados ainda é uma das minhas favoritas :-)
Szabolcs

@Szabolcs Sim, é muito legal. Você e Fred fizeram a maior parte, Bobby e eu adicionamos apenas alguns refinamentos, IIRC.
precisa

8

Esta é a receita do livro de Stan Wagon ... use-a quando o lote embutido se comporta de forma irregular devido à falta de precisão

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

Costumo usar o seguinte truque de Kristjan Kannike, quando preciso de um comportamento "tipo dicionário" a partir dos valores baixos do 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 os resultados da avaliação são confusos, às vezes ajuda despejar as etapas da avaliação em um arquivo 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]]

Uma amostra de uso seria ótima. Tente postar um quando tiver tempo.
perfil completo de belisarius

Você conhece Kristjan? Eu costumava trabalhar no mesmo grupo com ele em Helsinque. Cara legal, mundo pequeno.
Timo

Não, encontrou seu código na web. Na verdade, tentou enviar-lhe para corrigir um pequeno erro no código, mas o e-mail em sua página web não funciona mais
Yaroslav Bulatov

8

É possível executar o MathKernel no modo em lote usando opções de linha de comando não-batchinput-batchoutput documentadas e :

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

(onde input.mé o arquivo de entrada em lote que termina com o caractere de nova linha, outputfile.txté o arquivo para o qual a saída será redirecionada).

No Mathematica v.> = 6, o MathKernel possui uma opção de linha de comando não documentada:

-noicon

que controla se o MathKernel terá um ícone visível na barra de tarefas (pelo menos no Windows).

O FrontEnd (pelo menos da v.5) tem opção de linha de comando não documentada

-b

que desativa a tela inicial e permite executar o Mathematica FrontEnd muito mais rapidamente

e opção

-directlaunch

que desativa o mecanismo que inicia a versão mais recente do Mathematica instalada em vez de iniciar a versão associada aos arquivos .nb no registro do sistema.

Outra maneira de fazer isso provavelmente é :

Em vez de iniciar o binário Mathematica.exe no diretório de instalação, inicie o binário Mathematica.exe em SystemFiles \ FrontEnd \ Binaries \ Windows. O primeiro é um programa iniciador simples, que se esforça ao máximo para redirecionar solicitações de abertura de notebooks para cópias em execução da interface do usuário. O último é a própria interface do usuário binária.

É útil combinar a última opção de linha de comando com a configuração da opção global FrontEnd, VersionedPreferences->True que desativa o compartilhamento de preferências entre as diferentes versões do Mathematica instaladas :

SetOptions[$FrontEnd, VersionedPreferences -> True]

(O item acima deve ser avaliado na versão mais recente do Mathematica instalada.)

No Mathematica 8, isso é controlado na caixa de diálogo Preferências, no painel Sistema, na configuração "Criar e manter preferências de front end específicas da versão" .

É possível obter uma lista incompleta de opções de linha de comando do FrontEnd usando chave não documentada -h(o código para 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

Outras opções incluem:

-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

Existem outras opções de linha de comando potencialmente úteis do MathKernel e do FrontEnd? Por favor, compartilhe se você souber.

Pergunta relacionada .


"testemunha combinando?" O que isso significa?
Mr.Wizard

@ Mr.Wizard Provavelmente esta opção só faz sentido em sistemas de 64 bits em combinação com a opção -32e significa que a versão do MathKernel usada pelo FrontEnd corresponderá à versão do sistema operacional (64 bits). Parece que em outros casos essa opção não muda nada.
Alexey Popkov #

7

Meus hacks favoritos são pequenas macros geradoras de código que permitem substituir vários comandos padrão do clichê por um curto. Como alternativa, você pode criar comandos para abrir / criar blocos de anotações.

Aqui está o que eu tenho usado há algum tempo no meu fluxo de trabalho diário do Mathematica. Eu me vi fazendo o seguinte:

  1. Faça com que um notebook tenha um contexto privado, carregue pacotes que eu preciso, faça com que ele seja salvo automaticamente.
  2. Depois de trabalhar com este notebook por um tempo, eu gostaria de fazer alguns cálculos descartáveis ​​em um notebook separado, com seu próprio contexto privado, enquanto tenho acesso às definições que estou usando no notebook "principal". Como eu configuro o contexto privado, é necessário ajustar manualmente $ ContextPath

Fazer tudo isso repetidamente é uma dor, então vamos automatizar! Primeiro, algum código de utilitário:

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

Agora, vamos criar uma macro que irá colocar as seguintes células no bloco de anotações:

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

E aqui está a 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];
      ]
 ]

Agora, quando digito, MyPrivatize[]cria o contexto privado e carrega meu pacote padrão. Agora, vamos criar um comando que abrirá um novo bloco de anotações de rascunho com seu próprio contexto privado (para que você possa invadir lá com abandono sem o risco de estragar as definições), mas tenha acesso aos seus contextos atuais.

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

O legal disso é que SelfDestruct, quando o comando é executado, não deixa vestígios no bloco de anotações atual - o que é bom, porque, caso contrário, apenas criaria confusão.

Para obter pontos de estilo extras, você pode criar acionadores de palavras-chave para essas macros usando InputAutoReplacements, mas deixarei isso como um exercício para o leitor.


7

PutAppend com PageWidth -> Infinito

No Mathematica, o uso do PutAppendcomando é a maneira mais direta de manter um arquivo de log em execução com resultados de cálculos intermediários. Mas ele usa como PageWith->78configuração padrão ao exportar expressões para um arquivo e, portanto, não há garantia de que toda saída intermediária ocupe apenas uma linha no log.

PutAppendnão possui nenhuma opção em si, mas o rastreamento de suas avaliações revela que se baseia na OpenAppendfunção que possui a PageWithopção e permite alterar seu valor padrão pelo SetOptionscomando:

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

Assim, podemos PutAppendacrescentar apenas uma linha por vez, definindo:

SetOptions[OpenAppend, PageWidth -> Infinity]

ATUALIZAR

Há um bug introduzido na versão 10 (corrigido na versão 11.3): SetOptionsnão afeta mais o comportamento de OpenWritee OpenAppend.

Uma solução alternativa é implementar sua própria versão PutAppendcom a PageWidth -> Infinityopção explícita :

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

Observe que também podemos implementá-lo via WriteStringcomo mostrado nesta resposta, mas, neste caso, será necessário converter preliminarmente a expressão na InputFormvia correspondente ToString[expr, InputForm].


6

Eu estava apenas olhando através de um dos meus pacotes para inclusão na presente, e encontrou algumas mensagens que eu definido que maravilhas: Debug::<some name>. Por padrão, eles estão desativados, portanto, não produza muita sobrecarga. No entanto, posso agrupar meu código com eles e ativá-los se precisar descobrir exatamente como um pouco de código está se comportando.


Na Ajuda> Desde a versão 2.0 (lançada em 1991), o Debug foi substituído pelo Trace.
Dr. belisarius

1
@belisarius, você perdeu o ponto. Não é nem a Debugnem Tracefunções; é um conjunto de mensagens que criei com as quais posso jogar meu código para ativar / desativar à vontade. Eles são precedidos pela palavra Debug, da mesma maneira que uma usagemensagem é precedida pelo nome da função. Ele fornece a mesma funcionalidade que colocar várias coutinstruções no código c ++.
rcollyer

1
Ohh Desculpe. Fiquei confuso porque nunca me formei no jardim de infância por não aprender "As capitais são para os países": D
Dr. belisarius

6

Uma das coisas que me incomoda sobre as construções de escopo internas é que elas avaliam todas as definições de variáveis ​​locais de uma só vez, para que você não possa escrever, por exemplo.

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

Há pouco tempo, criei uma macro chamada WithNest que permite que você faça isso. Acho útil, pois permite manter ligações variáveis ​​locais sem precisar fazer algo como

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

No final, a melhor maneira de encontrar isso foi usando um símbolo especial para facilitar a repetição da lista de ligações, e coloquei a definição em seu próprio pacote para ocultar esse símbolo. Talvez alguém tenha uma solução mais simples para esse problema?

Se você quiser experimentar, coloque o seguinte em um arquivo chamado 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 publicou uma versão disso e faz referência à sua pergunta no MathGroup: stackoverflow.com/questions/4190845/custom-notation-question/…
Mr.Wizard

Obrigado por apontar isso! Já faz um tempo desde que eu olhei essas coisas, e é interessante ver todas essas outras abordagens.
precisa

5

Este foi escrito por Alberto Di Lullo, (que não parece estar no Stack Overflow).

CopyToClipboard, para o Mathematica 7 (no Mathematica 8 está embutido)

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

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

Eu achei essa rotina útil para copiar grandes números reais para a área de transferência na forma decimal comum. Por exemploCopyToClipboard["123456789.12345"]

Cell[OutputFormData@expr] remove as aspas ordenadamente.


5

Esse código cria uma paleta que carrega a seleção no Stack Exchange como uma imagem. No Windows, é fornecido um botão extra que fornece uma renderização mais fiel da seleção.

Copie o código em uma célula do notebook e avalie. Em seguida, retire a paleta da saída e instale-a usandoPalettes -> Install Palette...

Se você tiver algum problema, poste um comentário aqui. Faça o download da versão do notebook aqui .


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

Tenho certeza de que muitas pessoas encontraram a situação em que executam algumas coisas, percebendo que não apenas travaram o programa, mas também não salvaram nos últimos 10 minutos!

EDITAR

Depois de sofrer com isso por algum tempo, um dia descobri que é possível criar um salvamento automático a partir do código do Mathematica . Penso que o uso desse salvamento automático me ajudou muito no passado, e sempre achei que a possibilidade em si era algo que poucas pessoas sabem que podem fazer.

O código original que usei está na parte inferior. Graças aos comentários, descobri que é problemático e é muito melhor fazê-lo de uma maneira alternativa, usando ScheduledTask(que funcionará apenas no Mathematica 8).

O código para isso pode ser encontrado nesta resposta em Sjoerd C. de Vries (Como não tenho certeza se é bom copiá-lo para aqui, estou deixando-o apenas como um link.)


A solução abaixo está usando Dynamic. Ele salvará o notebook a cada 60 segundos, mas aparentemente apenas se sua célula estiver visível . Estou deixando aqui apenas por motivos de conclusão. (e para usuários do Mathematica 6 e 7)

/EDITAR

Para resolvê-lo, eu uso esse código no início de um notebook:

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

Isso salvará seu trabalho a cada 60 segundos.
Eu prefiroNotebookAutoSave[] porque salva antes de a entrada ser processada e porque alguns arquivos são mais texto do que entrada.

Encontrei-o aqui originalmente: http://en.wikipedia.org/wiki/Talk:Mathematica#Criticisms

Observe que, ao executar esta linha, o salvamento ocorrerá mesmo que você feche e abra novamente o arquivo (desde que a atualização dinâmica esteja ativada).

Além disso, como não há desfazer no Mathematica , tome cuidado para não excluir todo o seu conteúdo, pois o salvamento o tornará irreversível (como medida de precaução, removo esse código de todos os blocos de anotações concluídos)


você também pode salvá-lo com um nome diferente (por exemplo, anexando a hora e a data atuais ao final do nome do arquivo) e talvez em um diretório específico (por exemplo, "Backups"). isso seria como uma forma primitiva de versionamento.
quer

Você pode fazer algo assim NotebookSave[SelectedNotebook[], "work-" <> IntegerString[i] <> ".nb"]; i++, mas acho que qualquer tipo de referência ao nome atual do notebook se tornará recursivo.
tsvikas 8/08/11

2
Eu pensei que os Dynamicobjetos só são atualizados quando estão visíveis, então não tenho certeza se esse método funcionaria se, por exemplo, você rolar o Dynamicobjeto para fora da área visível. Então, novamente, eu não tentei. De qualquer forma, eu apenas a ofereci como sugestão.
Acl

1
Você pode testar isso usando Dynamic[Refresh[i++, UpdateInterval -> 1, TrackedSymbols -> {}]]. Role o número incremental de vista, espere um minuto, role para trás e veja se o número não é incrementado em 60. Sobre UpdateInterval: isso geralmente é usado se possível, mas se o seu código incluir variáveis ​​que mudam, essa alteração aciona uma nova atualização antes do intervalo termina. Experimente a linha acima semTrackedSymbols
Sjoerd C. de Vries

1
@ j0ker5 Experimente o meu código acima e você pode ver que o UpdateInterval nem sempre força as atualizações a serem espaçadas com o intervalo especificado. Este código também mostra que o Dynamic só funciona se a célula em que está contida estiver visível no front-end . Realmente para no momento em que está fora de vista. As pessoas realmente não devem confiar nesse código para salvar seus arquivos porque não. É perigoso
Sjoerd C. de Vries


3

Acho realmente útil ao desenvolver pacotes para adicionar esse atalho de teclado ao meu SystemFiles/FrontEnd/TextResources/Windows/KeyEventTranslations.trarquivo.

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

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

Em seguida, Packagename.mfaço cada PackagenameTest.nbbloco de notas para teste e as duas primeiras células do bloco de notas são definidas como células de inicialização. Na primeira célula eu coloquei

Needs["PackageManipulations`"]

para carregar a biblioteca PackageManipulations, muito útil, que foi escrita por Leonid. A segunda célula contém

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

que todos realizam o recarregamento real do pacote. Observe que as duas primeiras linhas existem apenas paraRemove todos os símbolos, pois eu gosto de manter os contextos o mais limpos possível.

Em seguida, o fluxo de trabalho para escrever e testar um pacote se torna algo assim.

  1. Salvar mudanças para Packagename.m .
  2. PackagenameTest.nbe faça CTRL + ALT + i.

Isso faz com que as células de inicialização recarregem o pacote, o que torna o teste muito simples.


1

A função a seguir format[expr_]pode ser usada para recuar / formatar mathematicaexpressões não formatadas que se estendem por uma 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 que você está usando isso na prática? A saída é um pouco "engraçada" para ser legível quando aplicada ao seu código ou aos dados (listas format@RandomInteger[10,{3,3}]): pastebin.com/nUT54Emq Como você já possui o básico e está interessado nisso, você pode melhorar o código para produzir uma formatação de fácil leitura? O próximo passo seria criar um botão de colar que criará uma célula de entrada com o código Mathematica bem recuado (de preferência preservando os comentários !!) Veja também minha pergunta relacionada .
Szabolcs
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.