Co znajduje się w Twojej torbie narzędziowej Mathematica? [Zamknięte]

152

Wszyscy wiemy, że Mathematica jest świetna, ale często brakuje jej krytycznej funkcjonalności. Jakich zewnętrznych pakietów / narzędzi / zasobów używasz w Mathematica?

Zmienię (i zaproszę do tego wszystkich innych) ten post główny, aby uwzględnić zasoby, które koncentrują się na ogólnym zastosowaniu w badaniach naukowych i które będą przydatne dla jak największej liczby osób. Zapraszam do przesyłania czegokolwiek, nawet małych fragmentów kodu (tak jak zrobiłem poniżej dla procedury synchronizacji).

Ponadto mile widziane są nieudokumentowane i przydatne funkcje w Mathematica 7 i nowszych, które znalazłeś lub wykopałeś z jakiegoś dokumentu / strony.

Prosimy o dołączenie krótkiego opisu lub komentarza, dlaczego coś jest świetne lub jakie zapewnia użyteczność. Jeśli umieszczasz linki do książek na Amazon za pomocą linków partnerskich, wspomnij o tym, np. Umieszczając swoje imię i nazwisko po łączu.


Pakiety:

  1. LevelSchemeto pakiet, który znacznie rozszerza możliwości Mathematica w tworzeniu ładnych wykresów. Używam go jeśli nie do niczego innego, to do znacznie, znacznie ulepszonej kontroli tików ramy / osi. Jego najnowsza wersja nosi nazwę SciDraw i zostanie wydana w tym roku.
  2. David Park's Presentation Package(50 USD - brak opłat za aktualizacje)
  3. grassmannOpsPakiet Jeremy'ego Michelsona zapewnia zasoby do wykonywania algebry i rachunku różniczkowego ze zmiennymi Grassmanna i operatorami, które mają nietrywialne relacje komutacji.
  4. GrassmannAlgebraPakiet i książka Johna Browna do pracy z algebrami Grassmanna i Clifforda.
  5. RISC (Research Institute for Symbolic Computation ) udostępnia do pobrania różne pakiety dla Mathematica (i innych języków). W szczególności istnieje teoria dotycząca automatycznego dowodzenia twierdzeń oraz wiele pakietów do sumowania symbolicznego, równań różnicowych itp. Na stronie oprogramowania grupy Algorithmic Combinatorics .

Przybory:

  1. MASHto doskonały skrypt Perla Daniela Reevesa, który zasadniczo zapewnia obsługę skryptów dla Mathematica v7. (Teraz wbudowany w Mathematica 8 z -scriptopcją).
  2. An alternate Mathematica shellz wejściem GNU readline (przy użyciu Pythona, tylko * nix)
  3. Pakiet ColourMaths umożliwia wizualne wybieranie części wyrażenia i manipulowanie nimi. http://www.dbaileyconsultancy.co.uk/colour_maths/colour_maths.html

Zasoby:

  1. Własne repozytorium Wolfram MathSourcema wiele przydatnych, jeśli wąskie notatniki do różnych zastosowań. Sprawdź również inne sekcje, takie jak

  2. Mathematica Wikibook .

Książki:

  1. Programowanie w matematyce: zaawansowane wprowadzenie autorstwa Leonida Shifrina ( web, pdf) to lektura obowiązkowa, jeśli chcesz zrobić coś więcej niż pętle For w programie Mathematica. Mamy przyjemność Leonidodpowiadać na pytania tutaj.
  2. Metody kwantowe z Mathematica autorstwa Jamesa F. Feagina ( amazon )
  3. The Mathematica Book autorstwa Stephena Wolframa ( amazon ) ( web)
  4. Zarys Schauma ( Amazon )
  5. Mathematica in Action autorstwa Stana Wagona ( amazon ) - 600 stron zgrabnych przykładów i przechodzi do wersji Mathematica 7. Techniki wizualizacji są szczególnie dobre, niektóre z nich można zobaczyć u autora Demonstrations Page.
  6. Podstawy programowania w Mathematica autorstwa Richarda Gaylorda ( pdf) - Dobre, zwięzłe wprowadzenie do większości tego, co powinieneś wiedzieć o programowaniu w Mathematica.
  7. Mathematica Cookbook autorstwa Sal Mangano opublikowana przez O'Reilly 2010 832 strony. - Napisane w znanym stylu książki kucharskiej O'Reilly: Problem - rozwiązanie. Do półproduktów.
  8. Równania różniczkowe z Mathematica, wyd. 3. Elsevier 2004 Amsterdam, autor: Martha L. Abell, James P. Braselton - 893 strony Dla początkujących, ucz się rozwiązywania DE i Mathematica w tym samym czasie.

Nieudokumentowane (lub słabo udokumentowane) funkcje:

  1. Jak dostosować skróty klawiaturowe Mathematica. Widziećthis question .
  2. Jak sprawdzić wzorce i funkcje używane przez własne funkcje Mathematica. Widziećthis answer
  3. Jak osiągnąć spójny rozmiar GraphPlots w Mathematica? Widziećthis question .
  4. Jak tworzyć dokumenty i prezentacje w Mathematica. Zobacz this question.
Dr belisarius
źródło
2
Mathematica 8 wychodzi z dużo lepszą integracją skryptów powłoki. wolfram.com/mathematica/new-in-8/mathematica-shell-scripts
Joshua Martell
2
+1, dla LevelScheme. Czasami jest trochę powolny. Ale ma rozsądną metodę tworzenia znaczników i znacznie łatwiej jest wtedy tworzyć układy graficzne godne dziennika Gridlub cokolwiek podobnego.
rcollyer
2
Jak zaproponował Alexey w komentarzach do tego pytania stackoverflow.com/questions/5152551/… , zaproponowałem zmianę nazwy tagu dla Mathematica tutaj: meta.stackexchange.com/questions/81152/… . Przyjrzyj się i zagłosuj za, jeśli się zgadzasz. Publikuję to tutaj, ponieważ to pytanie ma wiele ulubionych w społeczności MMA tutaj.
Dr. Belisarius
1
Wszystko, to pytanie naprawdę powinno być wiki społeczności ze wszystkich zwykłych powodów: nie ma poprawnej odpowiedzi i jest bardziej listą niż cokolwiek innego. Przepraszam wszystkich, którzy hojnie zyskali na reputacji dzięki temu pytaniu.
rcollyer
2
Te odpowiedzi na to pytanie są konstruktywne, należy je ponownie otworzyć.
MR

Odpowiedzi:

29

Pisałem to wcześniej, ale narzędzie znaleźć najbardziej przydatne jest stosowanie Reapi Sowktóry naśladuje / rozszerza zachowanie GatherBy:

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

Dzięki temu mogę grupować listy według dowolnych kryteriów i przekształcać je w trakcie. Sposób działania polega na tym, że funkcja kryterialna ( f) oznacza każdy element na liście, każdy element jest następnie przekształcany przez drugą podaną funkcję ( g), a określone wyjście jest kontrolowane przez trzecią funkcję ( h). Funkcja hprzyjmuje dwa argumenty: tag i listę zebranych elementów, które mają ten tag. Pozycje zachowują oryginalną kolejność, więc jeśli ustawisz h = #1&, otrzymasz nieposortowany Union, jak w przykładach dla Reap. Ale może być używany do wtórnego przetwarzania.

Jako przykład jego użyteczności pracowałem z Wannier90, który generuje zależny przestrzennie hamiltonian do pliku, w którym każda linia jest innym elementem macierzy, w następujący sposób

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

Aby przekształcić tę listę w zestaw macierzy, zebrałem wszystkie podlisty, które zawierają tę samą współrzędną, przekształciłem informacje o elementach w regułę (tj. {I, j} -> Re [Hij] + I Im [Hij]) i następnie przekształcił zebrane zasady w SparseArraywszystko z jednym wkładem:

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

Szczerze mówiąc, to jest mój szwajcarski scyzoryk i bardzo upraszcza złożone rzeczy. Większość moich innych narzędzi jest w pewnym stopniu specyficzna dla domeny, więc prawdopodobnie ich nie opublikuję. Jednak większość z nich, jeśli nie wszystkie, zawiera odniesienia SelectEquivalents.

Edycja : nie naśladuje całkowicie GatherBy, ponieważ nie może grupować wielu poziomów wyrażenia tak prosto, jak to GatherBymożliwe. Jednak Mapdziała dobrze w przypadku większości tego, czego potrzebuję.

Przykład : @Yaroslav Bulatov poprosił o samodzielny przykład. Oto jedno z moich badań, które zostało znacznie uproszczone. Więc powiedzmy, że mamy zbiór punktów na płaszczyźnie

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

i chcielibyśmy zredukować liczbę punktów o zestaw operacji symetrii. (Dla ciekawskich, tworzymy małą grupę każdego punktu.) W tym przykładzie użyjmy czterokrotnej osi obrotu wokół osi Z

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

Używając SelectEquivalentsmożemy pogrupować punkty, które tworzą ten sam zestaw obrazów w ramach tych operacji, tj. Są równoważne, używając następującego

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

co daje 3 podlisty zawierające równoważne punkty. (Uwaga, Unionjest tutaj absolutnie niezbędne, ponieważ zapewnia, że ​​ten sam obraz jest tworzony przez każdy punkt. Pierwotnie użyłem Sort, ale jeśli punkt leży na osi symetrii, jest niezmienny pod obrotem wokół tej osi, dając dodatkowy obraz samego siebie . Zatem Unioneliminuje te dodatkowe obrazy. Również GatherBydałoby ten sam wynik.) W tym przypadku punkty są już w formie, której będę używać, ale potrzebuję tylko reprezentatywnego punktu z każdej grupy i chciałbym policzyć równoważnych punktów. Ponieważ nie muszę przekształcać każdego punktu, używamIdentityfunkcja na drugiej pozycji. W przypadku trzeciej funkcji musimy być ostrożni. Pierwszym przekazanym argumentem będą obrazy punktów pod obrotami, które dla punktu {0,0,0}są listą czterech identycznych elementów, a użycie go zrzuciłoby zliczenie. Jednak drugi argument to tylko lista wszystkich elementów, które mają ten tag, więc będzie zawierał tylko {0,0,0}. W kodzie,

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

Uwaga, ten ostatni krok można równie łatwo wykonać za pomocą

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

Ale dzięki temu i mniej kompletnemu przykładowi powyżej łatwo jest zobaczyć, jak bardzo złożone transformacje są możliwe przy minimalnej ilości kodu.

rcollyer
źródło
Oryginalny kod Fortran77 został przebudowany w Święto Dziękczynienia 1996 i stąd przez wiele lat znany jako turkey.f ...: D Przy okazji bardzo ładna grafika. Przypomniał mi się potwór Falicova ...
Dr belizarius
@belisarius, nie czytałem historii, to zabawne. Właśnie zacząłem używać Wannier90, ale jest to jeden z najlepiej zorganizowanych i dobrze napisanych Fortrankodów, jakie widziałem. Prawie rozważam użycie Fortran...
rcollyer,
Zastanawiam się, czy mógłbyś dodać samodzielny przykład SelectEquivalents w akcji
Yaroslav Bulatov
@Yaroslav Bulatov, dodał przykład na żądanie. Daj mi znać, jeśli to pomoże. Jeśli tak się nie stanie, zobaczymy, co da się zrobić.
rcollyer
Pojawi się znacznik wyboru przy tym „pytaniu” dla najciekawszego fragmentu kodu.
Timo
57

Jedną z fajnych rzeczy w interfejsie notatnika Mathematica jest to, że może on oceniać wyrażenia w dowolnym języku, nie tylko w Mathematica. Jako prosty przykład rozważ utworzenie nowego typu komórki wejściowej Shell, która przekazuje zawarte wyrażenie do powłoki systemu operacyjnego w celu oceny.

Najpierw zdefiniuj funkcję, która deleguje ocenę polecenia tekstowego do powłoki zewnętrznej:

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

Drugi argument jest potrzebny i zignorowany z powodów, które ujawnią się później. Następnie chcemy stworzyć nowy styl o nazwie Shell :

  1. Otwórz nowy notatnik.
  2. Wybierz pozycję menu Format / Edytuj arkusz stylów ...
  3. W oknie dialogowym obok Podaj nazwę stylu: typ Shell.
  4. Wybierz nawias komórki obok nowego stylu.
  5. Wybierz pozycję menu Komórka / Pokaż wyrażenie
  6. Zastąp wyrażenie komórki tekstem kroku 6 podanym poniżej.
  7. Ponownie wybierz z menu pozycję Cell / Show Expression
  8. Zamknij okno.

Użyj następującego wyrażenia komórki jako tekstu kroku 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"]

Większość tego wyrażenia została skopiowana bezpośrednio z wbudowanego stylu programu . Kluczowe zmiany to te linie:

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

Evaluatablewłącza funkcjonalność SHIFT + ENTER dla komórki. Ocena wywoła CellEvaluationFunctionprzekazanie zawartości komórki i typu zawartości jako argumentów ( shellEvaluateignoruje drugi argument). CellFrameLabelsto tylko drobiazg, który pozwala użytkownikowi zidentyfikować, że ta komórka jest niezwykła.

Mając to wszystko na miejscu, możemy teraz wprowadzić i ocenić wyrażenie powłoki:

  1. W notatniku utworzonym w powyższych krokach utwórz pustą komórkę i wybierz nawias komórki.
  2. Wybierz pozycję menu Format / Styl / Powłoka .
  3. Wpisz do komórki prawidłowe polecenie powłoki systemu operacyjnego (np. „Ls” w systemie Unix lub „dir” w systemie Windows).
  4. Naciśnij klawisze SHIFT + ENTER.

Najlepiej jest zachować ten zdefiniowany styl w centralnie umieszczonym arkuszu stylów. Ponadto funkcje oceny, takie jak shellEvaluatesą najlepiej definiowane jako kody pośredniczące przy użyciu DeclarePackage w init.m. Szczegóły obu tych działań wykraczają poza zakres tej odpowiedzi.

Dzięki tej funkcji można tworzyć notatniki zawierające wyrażenia wejściowe w dowolnej składni. Funkcja oceny może być napisana w czystej postaci Mathematica lub delegować część lub wszystkie części oceny zewnętrznej agencji. Należy pamiętać, że istnieją inne haki, które odnoszą się do oceny komórek, jak CellEpilog, CellPrologi CellDynamicExpression.

Typowy wzorzec obejmuje zapisanie tekstu wyrażenia wejściowego do pliku tymczasowego, kompilację pliku w jakimś języku, uruchomienie programu i przechwycenie danych wyjściowych do ostatecznego wyświetlenia w komórce wyjściowej. Jest wiele szczegółów, na które należy zwrócić uwagę przy wdrażaniu pełnego rozwiązania tego rodzaju (np. Prawidłowe przechwytywanie komunikatów o błędach), ale należy docenić fakt, że takie rzeczy są nie tylko możliwe, ale praktyczne.

Z osobistego punktu widzenia to właśnie takie funkcje sprawiają, że interfejs notebooka jest centrum mojego wszechświata programowania.

Aktualizacja

Do tworzenia takich komórek przydatna jest następująca funkcja pomocnicza:

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

Jest używany w ten sposób:

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

Teraz, jeśli shellCell[]zostanie oszacowane, komórka wejściowa zostanie usunięta i zastąpiona nową komórką wejściową, która ocenia jej zawartość jako polecenie powłoki.

WReach
źródło
3
@WReach +100! Szkoda, że ​​nie wiedziałem o tym wcześniej! To jest bardzo przydatne, przynajmniej dla mnie. Dzięki za udostępnienie!
Leonid Shifrin,
To wygląda całkiem fajnie! CellEvaluationFunctionmoże być również użyty do hakowania składni niskiego poziomu.
Pan Wizard,
@Leonid Czy przynajmniej dla FrontEnd jest CellEvaluationFunctionhaczyk, którego szukałeś?
Pan Kreator
2
Ponadto: jest jeszcze jeden Cell opcja związana z oceną komórki - Evaluator -> "EvaluatorName". Znaczenie "EvaluatorName"można skonfigurować w oknie dialogowym Evaluation :: Kernel Configuration Options ... Nadal nie wiem, czy możliwe jest współkonfigurowanie go programowo ... Ta technika pozwala na używanie różnych MathKernels w różnych wersjach Cellw jednym Notatniku. Te MathKernels mogą pochodzić z różnych zainstalowanych wersji Mathematica .
Alexey Popkov
1
@Szabolcs Wszystkie moje własne zastosowania tej techniki obejmują plik podejście stdin _ / _ stdout, jak pokazano powyżej, lub samodzielne żądanie zdalne, takie jak zapytanie SQL lub operacja HTTP. Możesz spróbować skonfigurować aplikację internetową REPL w języku Python (w ten sposób ) i wchodzić z nią w interakcje przy użyciu Import, a może nawet uruchamiać zewnętrzny proces Pythona i komunikować się za pośrednictwem jego strumieni (np. Za pomocą Java ProcessBuilder ). Jestem pewien, że jest lepszy sposób Mathematica - brzmi jak dobre pytanie SO :)
WReach
36

Todd Gayley (Wolfram Research) właśnie przysłał mi fajny hack, który pozwala „opakować” wbudowane funkcje dowolnym kodem. Czuję, że muszę się podzielić tym przydatnym narzędziem. Poniżej znajduje się odpowiedź Todda na mój question.

Trochę interesującej (?) Historii: ten styl hackowania "zawijania" wbudowanej funkcji został wynaleziony około 1994 roku przez Robby'ego Villegasa i mnie, jak na ironię dla funkcji Message, w pakiecie o nazwie ErrorHelp, który napisałem dla Mathematica Journal wtedy. Od tamtej pory był używany wielokrotnie, przez wiele osób. To trochę sztuczka insiderów, ale myślę, że można uczciwie powiedzieć, że stało się to kanonicznym sposobem wstrzykiwania własnego kodu do definicji funkcji wbudowanej. Dobrze wykonuje swoją pracę. Możesz oczywiście umieścić zmienną $ inMsg w dowolnym prywatnym kontekście.

Unprotect[Message];

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

Protect[Message];
Alexey Popkov
źródło
@Alexey Mam trudności ze zrozumieniem tego. Czy mógłbyś wyjaśnić, jak to działa? Czy nie powinno być gdzieś komunikatu „Unprotect [Wiadomość]”? I czy ten przykład nie zawiera nieskończonej rekurencji? I, ! TrueQ [$ inMsg] czy ma to sens, gdy $ inMsg jest zdefiniowane w zakresie Block i niezdefiniowane poza Block?
Sjoerd C. de Vries
9
@Sjoerd Z tego, co rozumiem, Unprotectrzeczywiście musi być, zostało po prostu pominięte. Celem Block(dynamicznego określania zakresu) i $inMsgjest właśnie zapobieganie nieskończonej rekurencji. Ponieważ $inMsgjest niezdefiniowana na zewnątrz (jest to ważny wymóg), na początku TrueQszacuje się do Falsei wchodzimy do treści funkcji. Ale kiedy mamy wywołanie funkcji wewnątrz ciała, warunek ocenia się na False(ponieważ zmienna została przedefiniowana przez Block). W związku z tym reguła zdefiniowana przez użytkownika nie jest dopasowywana, a zamiast niej używana jest reguła wbudowana.
Leonid Shifrin
1
@Leonid Dzięki, teraz rozumiem. Bardzo mądry!
Sjoerd C. de Vries,
1
Właśnie odkryłem, że ta technika została omówiona przez Robby'ego Villegasa z Wolfram Research na konferencji deweloperów w 1999 roku. Zobacz notatnik „Praca z wyrażeniami nieocenionymi” zamieszczony tutaj . W tym notatniku Robby Villegas omawia tę sztuczkę w podrozdziale „Moja sztuczka blokowa do przechwytywania wywołań funkcji wbudowanych”.
Alexey Popkov
1
@ Mr.Wizard To nie jedyny sposób, aby to zrobić. Przez długi czas korzystałem z wersji, w której przedefiniowujesz DownValuesw czasie wykonywania, możesz spojrzeć na ten post groups.google.com/group/comp.soft-sys.math.mathematica/ ... na przykład ( SetDelayedredefinition) . Ale moja metoda jest mniej elegancka, mniej niezawodna, bardziej podatna na błędy i sprawia, że ​​odejście od rekurencji jest znacznie mniej proste w implementacji. Tak więc w większości sytuacji metoda opisana przez @Alexey wygrywa.
Leonid Shifrin
25

Nie jest to kompletny zasób, więc wrzucam go tutaj w sekcji odpowiedzi, ale uznałem go za bardzo przydatny przy rozwiązywaniu problemów z szybkością (co niestety jest dużą częścią tego, o co chodzi w programowaniu w 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};

Użycie jest wtedy proste timeAvg@funcYouWantToTest.

EDIT: Pan Kreator dostarczył prostszą wersję, która znosi Throwi Catchi jest nieco łatwiejsze do analizowania:

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

EDYCJA: Oto wersja z ACL (pobrana stąd ):

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]
Timo
źródło
Zrobiłem to jeszcze raz i jeszcze raz ... czas wejść do mojej własnej torby. tnx!
Dr. Belisarius
1
Jeden problem z tym kodem (cóż, może to być punkt widzenia perfekcjonisty) polega na tym, że możemy złapać coś, czego nie rzuciliśmy, i zinterpretować to jako nieprawidłowy wynik synchronizacji. Oba Catchi Throwpowinny być używane z unikalnymi tagami wyjątków.
Leonid Shifrin,
2
Timo, cieszę się, że podoba ci się moja interpretacja na tyle, aby ją uwzględnić. Dziękuję również za przyznanie mi kredytu. Ciekawi mnie sposób, w jaki przeformatowałeś mój kod. Nie kieruję się żadnymi konkretnymi wytycznymi w moim własnym kodzie, poza tym, że sam ułatwiam czytanie; Czy za Twoim ponownym formatowaniem stoi jakaś szkoła myślenia, czy jest to tylko preferencja? Mathematica nie zachęca do precyzyjnego formatowania kodu ze względu na sposób, w jaki przepływa dane wejściowe, ale umieszczanie kodu w tym miejscu powoduje, że zaczynam o tym myśleć. Swoją drogą, myślę, że masz na myśli „ Throwi Catch”, a nie „ Reapi Sow”.
Pan Czarodziej,
1
@Simon, panie Wizard, używam tej metody do czasowych różnych wersji niewielkich funkcji, które będą wywoływane wiele razy. Niekoniecznie w strukturze pętli, ale z pewnością w konstrukcjach optymalizowanych przez MMA. W tym kontekście synchronizacja wykonania pętli ma sens, a wydajność będzie zbliżona do rzeczywistej aplikacji. W przypadku taktowania dużych, złożonych funkcji (może nawet całych komórek inicjalizacyjnych) metoda Simona da lepszy wynik. Podsumowując, bardziej interesują mnie wartości względne i każda metoda powinna tam działać.
Timo
3
Teraz RepeatedTimingtrzeba to zrobić.
masterxilo
20

Internal`InheritedBlock

Niedawno dowiedziałem się o istnieniu tak użytecznej funkcji jak Internal`InheritedBlockz wiadomości Daniela Lichtblau w oficjalnej grupie dyskusyjnej.

Jak rozumiem, Internal`InheritedBlockpozwala na przekazanie kopii funkcji wychodzącej wewnątrz Blockzakresu:

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]

Myślę, że ta funkcja może być bardzo przydatna dla każdego, kto musi tymczasowo zmodyfikować wbudowane funkcje!

Porównanie z Block

Zdefiniujmy jakąś funkcję:

a := Print[b]

Teraz chcemy przekazać kopię tej funkcji do Blockzakresu. Naiwna próba nie daje tego, czego chcemy:

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

During evaluation of In[9]:= b

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

Teraz próbuję użyć opóźnionej definicji w pierwszym argumencie Block(jest to również funkcja nieudokumentowana):

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

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

During evaluation of In[3]:= b

Widzimy, że w tym przypadku adziała, ale nie mamy kopii oryginału aw Blocklunecie.

Teraz spróbujmy Internal`InheritedBlock:

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

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

Mamy kopię oryginalnej definicji awewnątrz Blockzakresu i możemy ją zmodyfikować w dowolny sposób bez wpływu na globalną definicję a!

Alexey Popkov
źródło
+1 Bardzo przydatne! Jeszcze jedno narzędzie w torbie i 10 punktów bliżej do uprawnienia do edycji.
Mr.Wizard
Wydaje mi się, że jest to wariant wczesnej lub późnej oceny lub jej braku i pełnej oceny.
user2432923
19

Mathematica to ostre narzędzie, ale może cię zranić swoim nieco nietypowym zachowaniem i lawiną tajemniczych komunikatów diagnostycznych . Jednym ze sposobów radzenia sobie z tym jest zdefiniowanie funkcji według tego idiomu:

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

To dużo schematów, które często kuszę, aby pomijać. Zwłaszcza podczas prototypowania, co w Mathematica często się zdarza. Tak więc używam makra o nazwie, definektóre pozwala mi zachować dyscyplinę, przy znacznie mniejszym schemacie.

Podstawowe użycie definejest takie:

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

fact[5]

120

Na początku nie wygląda to na dużo, ale są pewne ukryte korzyści. Pierwsza usługadefine zapewnia, to automatyczne zastosowanie ClearAlldo definiowanego symbolu. Gwarantuje to, że nie ma żadnych resztek definicji - co jest częstym zjawiskiem podczas początkowego tworzenia funkcji.

Druga usługa polega na tym, że definiowana funkcja jest automatycznie „zamykana”. Rozumiem przez to, że funkcja wyśle ​​komunikat i przerwie działanie, jeśli zostanie wywołana z listą argumentów, która nie jest zgodna z żadną z definicji:

fact[-1]

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

To jest podstawowa wartość define , która wyłapuje bardzo powszechną klasę błędów.

Innym udogodnieniem jest zwięzły sposób określania atrybutów definiowanej funkcji. Zróbmy funkcję Listable:

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

fact[{3, 5, 8}]

{6, 120, 40320}

Oprócz wszystkich normalnych atrybutów defineakceptuje dodatkowy atrybut o nazwie Open. Zapobiega to definedodawaniu definicji błędu typu catch-all do funkcji:

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

successor /@ {1, "hi"}

{2, successor["hi"]}

Dla funkcji można zdefiniować wiele atrybutów:

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

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

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

Bez zbędnych ceregieli, oto definicja 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: ``";

Przedstawiona implementacja nie obsługuje wartości w górę ani curry, ani wzorców bardziej ogólnych niż prosta definicja funkcji. Pozostaje jednak przydatna.

WReach
źródło
2
+1 - to naprawdę przydatna rzecz. Używałem podobnych narzędzi. Makra (podobnie jak introspekcja i inne techniki metaprogramowania) mogą być bardzo potężne, ale wydają się być ogólnie niedoceniane w społeczności Mathematica, a przynajmniej takie było moje wrażenie.
Leonid Shifrin
Właśnie zdefiniowałem coś podobnego. +1 dla obsługi CompoundExpression do robienia wielu definicji, Abort [] (wydaje się lepsze niż jeszcze więcej wiadomości) i Open (dobre dla np. Konstruktorów).
masterxilo
16

Zacznij bez otwartego pustego notatnika

Martwiło mnie, że Mathematica zaczynała od pustego zeszytu. Mógłbym zamknąć ten notatnik skryptem, ale i tak by się przez chwilę otworzył. Mój hack polega na utworzeniu pliku Invisible.nbzawierającego:

Notebook[{},Visible->False]

I dodaj to do mojego Kernel\init.m:

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

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

Teraz zaczynam Mathematica od otwarcia Invisible.nb

Może jest lepszy sposób, ale to mi dobrze służyło.


Dostosowane FoldiFoldList

Fold[f, x] jest równoważne Fold[f, First@x, Rest@x]

Nawiasem mówiąc, uważam, że może się to znaleźć w przyszłej wersji Mathematica.

Niespodzianka! Zostało to wdrożone, chociaż obecnie nie jest to udokumentowane. Poinformowano mnie, że został on wdrożony w 2011 roku przez Olivera Ruebenkoeniga, podobno niedługo po tym, jak to opublikowałem. Dziękuję 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]

Zaktualizowano, aby to umożliwić:

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

„Partycja dynamiczna”

Zobacz Mathematica.SE post # 7512 dla nowej wersji tej funkcji.

Często chcę podzielić listę według kolejności długości.

przykład pseudokodu:

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

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

Wymyśliłem to:

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

Które następnie zakończyłem tym, w tym testowaniem argumentów:

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

Trzeci argument kontroluje, co dzieje się z elementami poza specyfikacją podziału.


Sztuczki Szabolcsa Mathematica

Najczęściej używam palety Wklej dane tabelaryczne

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

Modyfikuj dane zewnętrzne z poziomu Compile

Ostatnio Daniel Lichtblau pokazał metodę, której nigdy wcześniej nie widziałem. Moim zdaniem znacznie zwiększa użytecznośćCompile

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.}  *)
Mr.Wizard
źródło
3
+1 Dobra kolekcja! Jeśli chodzi o zewnętrzne modyfikacje od wewnątrz Compile- cały mój post tutaj: stackoverflow.com/questions/5246330/… , miał na celu zaprezentowanie tej możliwości w nietrywialnym ustawieniu (było już tam zamieszczone krótsze i szybsze rozwiązanie omawianego problemu) . IMO, największą wygraną jest tutaj możliwość emulacji przekazywania przez odniesienie i dzielenia dużych skompilowanych funkcji na łatwiejsze do zarządzania i wielokrotnego użytku fragmenty.
Leonid Shifrin,
1
Można również dostosować informacje składni Fold i FoldList w swojej nowej definicji: SyntaxInformation [Fold] = { "ArgumentsPattern" -> {_, . , _}}; SyntaxInformation [FoldList] = {"ArgumentsPattern" -> {_, _., {_ }}};
faysou
14

Ogólne problemy i rozwiązania dotyczące eksportu PDF / EMF

1) Jest to całkowicie nieoczekiwane i nieudokumentowane, ale Mathematica eksportuje i zapisuje grafikę w formatach PDF i EPS przy użyciu zestawu definicji stylów, który różni się od używanego do wyświetlania notatników na ekranie. Domyślnie Notatniki są wyświetlane na ekranie w środowisku stylu „Praca” (co jest wartością domyślną dla opcji ScreenStyleEvironmentglobalnej $FrontEnd), ale są drukowane w "Printout"środowisku stylu (co jest wartością domyślną dla opcji PrintingStyleEnvironmentglobalnej $FrontEnd). Kiedy eksportuje się grafikę w formatach rastrowych, takich jak GIF i PNG lub w formacie EMF, do renderowania używane jest środowisko w stylu Mathematica generuje grafikę, która wygląda dokładnie tak, jak wygląda w programie Notebook. Wygląda na to, że"Working" . Ale tak nie jest, gdy eksportujesz / zapisujesz cokolwiek w formatach PDF lub EPS! W tym przypadku "Printout"środowisko stylu jest używane domyślnie bardzo różni się to od środowiska stylu pracy. Przede wszystkim, że "Printout"zestawy styl miejsca Magnificationdo 80% . Po drugie, używa własnych wartości dla rozmiarów czcionek w różnych stylach, co powoduje niespójne zmiany rozmiaru czcionki w wygenerowanym pliku PDF w porównaniu z oryginalną reprezentacją na ekranie. Te ostatnie można nazwać fluktuacjami FontSize, które są bardzo irytujące. Ale na szczęście można tego uniknąć , ustawiając opcję PrintingStyleEnvironmentglobalną $FrontEndna „Praca” :

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

2) Powszechnym problemem związanym z eksportowaniem do formatu EMF jest to, że większość programów (nie tylko Mathematica ) generuje plik, który wygląda ładnie przy domyślnym rozmiarze, ale staje się brzydki po powiększeniu. Dzieje się tak, ponieważ metapliki są próbkowane z wierną rozdzielczością ekranu . Jakość wygenerowanego pliku EMF można Magnifypoprawić, wprowadzając oryginalny obiekt graficzny, dzięki czemu dokładność próbkowania oryginalnej grafiki staje się znacznie bardziej precyzyjna. Porównaj dwa pliki:

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

Jeśli wstawisz te pliki do programu Microsoft Word i powiększysz je, zobaczysz, że pierwsze „a” ma na nim ząb piłowany, a drugie nie (testowane z Mathematica 6).

Inne rozwiązanie ImageResolutionzasugerował Chris Degnen (ta opcja działa przynajmniej począwszy od Mathematica 8):

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

3) W Mathematica mamy trzy sposoby na konwersję grafiki do metapliku: poprzez Exportdo "EMF"(zdecydowanie zalecany sposób: tworzy metaplik o najwyższej możliwej jakości), poprzez Save selection As...pozycję menu ( tworzy znacznie mniej dokładną figurę , niezalecane) i poprzez Edit ► Copy As ► Metafilepozycję menu ( zdecydowanie polecam przeciwko tej trasie ).

Alexey Popkov
źródło
13

Na popularne żądanie kod do generowania wykresu 10 najlepszych odpowiedzi na SO (z wyjątkiem adnotacji ) przy użyciu SO API .

wprowadź opis obrazu tutaj

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", ""})]
Sjoerd C. de Vries
źródło
1
Brett zadał pytanie o prawie ten dokładny kod. Może jest tam najbardziej odpowiedni, z poprawką lub dwoma, aby pasowały do ​​pytania. Właściwie byłbym wart reputacji, w przeciwieństwie do tego pytania.
rcollyer,
@rcollyer ma rację. To jest „Społeczność Wiki”
Dr. belisarius,
@belisarius Właśnie skopiowałem to w odpowiedzi na pytanie Bretta ...
Sjoerd C. de Vries
@Sjoerd Twoja działka tutaj nie aktualizuje się automatycznie.
Dr belisarius
@belisarius Właściwie miałem nadzieję, że podejmiesz się tego zadania ... ;-)
Sjoerd C. de Vries
13

Wyrażenia buforowania

Uważam, że te funkcje są bardzo pomocne w buforowaniu dowolnego wyrażenia. Ciekawą rzeczą w przypadku tych dwóch funkcji jest to, że samo przetrzymywane wyrażenie jest używane jako klucz pamięci podręcznej tablicy / symbolu lub CacheIndex, w porównaniu do dobrze znanego zapamiętywania w mathematica, w którym można buforować wynik tylko wtedy, gdy funkcja jest zdefiniowana jak f [x_]: = f [x] = ... Więc możesz buforować dowolną część kodu, jest to przydatne, jeśli funkcja ma być wywoływana kilka razy, ale tylko niektóre części kodu nie mogą być ponownie obliczane.

Aby buforować wyrażenie niezależnie od jego argumentów.

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

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

Za drugim razem wyrażenie zwraca 6 bez czekania.

Aby buforować wyrażenie przy użyciu wyrażenia aliasu, które może zależeć od argumentu wyrażenia w pamięci podręcznej.

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

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

Jeśli obliczenie wyrażenia zajmuje trochę czasu, znacznie szybciej jest oszacować {"f", 2}, na przykład w celu pobrania wyniku z pamięci podręcznej.

Odmiana tych funkcji, aby mieć zlokalizowaną pamięć podręczną (tj. Pamięć podręczna jest automatycznie zwalniana poza konstrukcją Block), zobacz ten post Unikaj powtarzających się wywołań interpolacji

Usuwanie wartości z pamięci podręcznej

Aby usunąć wartości zapisane w pamięci podręcznej, gdy nie znasz liczby definicji funkcji. Uważam, że definicje mają gdzieś puste miejsce w swoich argumentach.

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

Aby usunąć wartości zapisane w pamięci podręcznej, gdy znasz liczbę definicji funkcji (działa nieco szybciej).

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

Wykorzystuje to fakt, że definicje funkcji znajdują się na końcu ich listy DownValues, a buforowane wartości znajdują się przed.

Używanie symboli do przechowywania danych i funkcji podobnych do obiektów

Również tutaj są interesujące funkcje do używania symboli, takich jak obiekty.

Powszechnie wiadomo, że można przechowywać dane w symbolach i szybko uzyskiwać do nich dostęp za pomocą DownValues

mysymbol["property"]=2;

Możesz uzyskać dostęp do listy kluczy (lub właściwości) symbolu za pomocą tych funkcji w oparciu o to, co dreeves przesłał w poście na tej stronie:

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

Często używam tej funkcji, aby wyświetlić wszystkie informacje zawarte w DownValues ​​symbolu:

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

Wreszcie, oto prosty sposób na stworzenie symbolu, który zachowuje się jak obiekt w programowaniu obiektowym (po prostu odtwarza najbardziej podstawowe zachowanie OOP, ale uważam składnię za elegancką):

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

Właściwości są przechowywane jako DownValues, a metody jako opóźnione Upvalues ​​w symbolu utworzonym przez Module, który jest zwracany. Znalazłem składnię function2, która jest zwykłą składnią OO dla funkcji w strukturze danych drzewa w Mathematica .

Aby zapoznać się z listą istniejących typów wartości, które ma każdy symbol, zobacz http://reference.wolfram.com/mathematica/tutorial/PatternsAndTransformationRules.html i http://www.verbeia.com/mathematica/tips/HTMLLinks/Tricks_Misc_4.html .

Na przykład spróbuj tego

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

Możesz przejść dalej, jeśli chcesz emulować dziedziczenie obiektów za pomocą pakietu o nazwie InheritRules dostępnego tutaj http://library.wolfram.com/infocenter/MathSource/671/

Możesz również przechowywać definicję funkcji nie w newObject, ale w symbolu typu, więc jeśli NewObject zwrócił typ [newObject] zamiast newObject, możesz zdefiniować funkcję i funkcję2 w ten sposób poza NewObject (a nie wewnątrz) i mieć takie samo zastosowanie jak poprzednio .

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

Użyj UpValues ​​[typ], aby zobaczyć, że funkcja i funkcja2 są zdefiniowane w symbolu typu.

Dalsze pomysły dotyczące tej ostatniej składni przedstawiono tutaj https://mathematica.stackexchange.com/a/999/66 .

Ulepszona wersja SelectEquivalents

@rcollyer: Wielkie dzięki za udostępnienie SelectEquivalents, to niesamowita funkcja. Oto ulepszona wersja SelectEquivalents wymienionych powyżej z większymi możliwościami i korzystaniem z opcji, dzięki czemu jest łatwiejsza w użyciu.

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

Oto przykłady wykorzystania tej wersji:

Prawidłowe korzystanie z Mathematica Gather / Collect

Jak wykonałbyś funkcję tabeli przestawnej w Mathematica?

Szybki algorytm binningu 2D Mathematica

Torba wewnętrzna

Daniel Lichtblau opisuje tutaj interesującą wewnętrzną strukturę danych dla rosnących list.

Implementacja Quadtree w Mathematica

Funkcje debugowania

Te dwa posty wskazują przydatne funkcje do debugowania:

Jak debugować podczas pisania małych lub dużych kodów za pomocą Mathematica? stoł warsztatowy? debugger mma? albo coś innego? (Pokaż to)

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

Oto kolejna funkcja oparta na Reap and Sow do wyodrębniania wyrażeń z różnych części programu i przechowywania ich w symbolu.

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

Oto przykład

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

Inne zasoby

Oto lista interesujących linków do celów edukacyjnych:

Zbiór zasobów edukacyjnych Mathematica

Zaktualizowano tutaj: https://mathematica.stackexchange.com/a/259/66

faysou
źródło
Powiązane: „ Najlepszy sposób na zbudowanie funkcji z pamięcią ”. WReach podał niesamowity przykład prostej funkcji, która nie tylko zapamiętuje swoje wartości, ale także zapisuje je do pliku i odczytuje wstecz po ponownym uruchomieniu.
Alexey Popkov
1
Powiązane: „ Mathematica: Jak wyczyścić pamięć podręczną dla symbolu, tj. Nieustawione wartości DownValues ​​bez wzorca ”. To pytanie pokazuje, jak wyczyścić pamięć podręczną przy użyciu standardowej f[x_] := f[x] = some codezapamiętania.
Simon
7
+1 Jest wygodna notacja, która eliminuje potrzebę powtarzania lewej strony definicji w funkcji buforującej, np c:Cache[expr_] := c = expr. : .
WReach
Ładny wariant SelectEquivalents. Myślę, że TagOnElementjako drugi parametr pozostawiłbym domyślne ustawienie, Identityponieważ jest najczęściej używany z nich. Myślę, że też nie bym go włączył FinalOp, ponieważ można sobie z tym poradzić OpOnTaggedElems. Skróciłbym również nazwy opcji, ponieważ ich długość sprawia, że ​​pisanie jest niewygodne. Spróbuj TagFunction, TransformElement, TransformResults, a TagPatternzamiast tego. Oba, TagPatterni MapLevelsą świetne dodatki do funkcjonalności, a dobry przepisać wierzchnie.
rcollyer
Dzięki za komentarz rcollyer. Wziąłem to pod uwagę i poprawiłem także czytelność kodu. Zachowuję FinalFunction, ponieważ działa na wyniku Reap, na przykład jeśli chcesz posortować wynik końcowy według tagów, jeśli je zachowasz.
faysou
12

Moje funkcje narzędziowe (mam je wbudowane w MASH, o czym jest mowa w pytaniu):

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).   *)
dreeves
źródło
Informacje na temat funkcji „each” można znaleźć na stronie stackoverflow.com/questions/160216/foreach-loop-in-mathematica
dreeves
11

Jedna sztuczka, której użyłem, która pozwala na emulację sposobu, w jaki większość wbudowanych funkcji działa ze złymi argumentami (wysyłając wiadomość, a następnie zwracając cały formularz bez oceny), wykorzystuje dziwaczny sposób Conditiondziałania, gdy jest używany w definicji. Jeśli foopowinno działać tylko z jednym argumentem:

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

Jeśli masz bardziej złożone potrzeby, łatwo jest rozliczyć walidację argumentów i generowanie wiadomości jako niezależną funkcję. Możesz zrobić bardziej skomplikowane rzeczy, używając efektów ubocznych Conditionnie tylko do generowania wiadomości, ale moim zdaniem większość z nich należy do kategorii „marny hack” i należy ich unikać, jeśli to możliwe.

Ponadto w kategorii „metaprogramming”, jeśli masz .mplik package ( ) programu Mathematica , możesz użyć "HeldExpressions"elementu, aby uzyskać wszystkie wyrażenia zawarte w pliku HoldComplete. To sprawia, że ​​śledzenie rzeczy jest znacznie łatwiejsze niż korzystanie z wyszukiwania tekstowego. Niestety, nie ma łatwego sposobu na zrobienie tego samego z notebookiem, ale możesz uzyskać wszystkie wyrażenia wejściowe za pomocą czegoś takiego:

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

Wreszcie, możesz wykorzystać fakt, że Moduleemuluje zamknięcia leksykalne, aby stworzyć odpowiednik typów referencyjnych. Oto prosty stos (który wykorzystuje odmianę Conditionsztuczki do obsługi błędów jako 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]

Teraz możesz wydrukować elementy listy w odwrotnej kolejności w niepotrzebnie zawiły sposób!

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

 While[!EmptyQ[stack],
  Print[Peek@stack];
  Pop@stack]]
Pillsy
źródło
1
+1 dla HeldExpressionselementu w pakietach nie był tego świadomy. Zwykle importowałem jako ciąg, a następnie używałem ToExpressionz HoldCompletejako ostatni argument. Odnośnie używania Conditiondla wiadomości - jest to standardowa technika w pisaniu pakietów od co najmniej 1994 roku. Odnośnie trwałości poprzez Modulevars - jakiś czas temu miałem długi post na ten temat na Mathgroup: groups.google.com/group/comp.soft- sys.math.mathematica /… (mój trzeci post w tym wątku), jest to podobne i zawiera linki do kilku nietrywialnych przykładów użycia.
Leonid Shifrin,
@Leonid Shifrin: Podniosłem to Conditionjako wiedzę, prawdopodobnie od współpracownika, ale nie zdawałem sobie sprawy, że to standardowa technika. Link dotyczący używania Modulesymboli jako typów referencyjnych jest interesujący!
Pillsy,
+1, nigdy o tym nie myślałem. Im więcej dowiaduję się o tym języku, tym wydaje się potężniejszy.
rcollyer,
@Pillsy Jaki jest cel tworzenia stosu w ten sposób?
Pan Wizard
@ Mr.Wizard: Właśnie wybrałem jedną z najprostszych mutowalnych struktur danych, jakie mogłem wymyślić, aby zilustrować tę technikę.
Pillsy
11

Drukowanie definicji symboli systemu bez dołączonego kontekstu

Poniższa contextFreeDefinition[]funkcja spróbuje wydrukować definicję symbolu bez dołączonego najczęściej używanego kontekstu. Definicję można następnie skopiować do Workbencha i sformatować pod kątem czytelności (wybierz ją, kliknij prawym przyciskiem myszy, Źródło -> 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 []

Zastrzeżenie: Ta funkcja nie jest lokalizowanie zmiennych w ten sam sposób Withi Modulezrobić, co oznacza, że zagnieżdżone konstrukcje lokalizacyjne nie działać będzie zgodnie z oczekiwaniami. withRules[{a -> 1, b -> 2}, With[{a=3}, b_ :> b]] będzie zastąpić ai bw zagnieżdżona Withi Rule, a Withtego nie robi.

Jest to wariant, Withktóry używa reguł zamiast =i :=:

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

Okazało się to przydatne podczas porządkowania kodu napisanego podczas eksperymentów i lokalizowania zmiennych. Czasami otrzymuję listy parametrów w postaci {par1 -> 1.1, par2 -> 2.2}. Z withRulesparametrem wartości są łatwo wprowadzić do kodu uprzednio pisemnej za pomocą zmiennych globalnych.

Użycie jest takie jak With:

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

Antyaliasing grafiki 3D

Jest to bardzo prosta technika usuwania grafiki 3D, nawet jeśli twój sprzęt graficzny nie obsługuje jej natywnie.

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

Oto przykład:

Grafika Mathematica Grafika Mathematica

Należy zauważyć, że duża wartość nlub duży rozmiar obrazu zwykle ujawniają błędy sterownika karty graficznej lub wprowadzają artefakty.


Funkcja porównywania notebooków

Funkcjonalność porównywania notesów jest dostępna w <<AuthorTools`pakiecie i (przynajmniej w wersji 8) w nieudokumentowanym NotebookTools`kontekście. To jest mały GUI do porównania dwóch obecnie otwartych notatników:

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

Grafika Mathematica

Szabolcs
źródło
Wszystko byłoby fajne, ale tak naprawdę nie lokalizuje zmiennych, jak widać, przypisując say a = 3; b = 4;przed przykładowym wywołaniem, a następnie wywołać withRules. Można zapisać go zamiast przy użyciu następujących: SetAttributes[withRules, HoldAll];withRules[rules_, expr_] := Unevaluated[expr] /. Unevaluated[rules]. Różnice w semantyce w Withtamtych czasach: 1. strony reguł nie są teraz oceniane 2. withRulesnie rozwiązuje konfliktów nazewnictwa z wewnętrznymi konstrukcjami określającymi zasięg With. Ta ostatnia jest dość poważna - w zależności od przypadku jest dobra lub zła.
Leonid Shifrin
@Leonid Masz całkowitą rację, wydaje mi się, że nigdy nie uczę się prawidłowego sprawdzania kodu przed wysłaniem ... kiedy tego używam, praktycznie nigdy nie przypisuję wartości zmiennym, ale to dość poważny problem, masz rację. Co myślisz o poprawionej wersji? (Nie obchodzi mnie nieobsługiwanie zagnieżdżonych Withs. To nie zawsze działa również z wbudowanymi konstrukcjami lokalizacji, np With[{a=1}, Block[{a=2}, a]]. Czy uważasz, że jest dobry powód, dla którego zagnieżdżone Blocknie lokalizują się tam, tak jak zagnieżdżone Withi Moduletak?)
Szabolcs
@Leonid nie użyłem po prostu, Unevaluated[rules]ponieważ chciałem x -> 1+1ocenić RHS.
Szabolcs
@Leonid Masz rację, problem z zagnieżdżoną lokalizacją może być dość poważny. Myślę, że zagnieżdżone Withs są łatwe do wykrycia i uniknięcia, ale wzorce nie: With[{a = 1}, a_ -> a]lokalizuje wewnętrzne, aa withRulesnie. Czy wiesz, czy istnieje sposób, aby uzyskać dostęp do wewnętrznego mechanizmu lokalizacji Mathematica i stworzyć nowe konstrukcje (podobne do Rule), które również lokalizują? Prawdopodobnie usunę tę odpowiedź później, ponieważ jest bardziej niebezpieczna niż użyteczna, ale najpierw chciałbym się nią pobawić.
Szabolcs
Myślę, że twoje użycie InheritedBlockjest całkiem fajne i bardzo elegancko rozwiązuje problem. Jeśli chodzi o konflikty zakresu, zwykle powiązania dla leksykalnego określania zakresu mają miejsce w „czasie leksykalnego wiązania”, czyli - przed uruchomieniem, podczas gdy dynamiczne określanie zakresu wiąże się w czasie wykonywania, co może to wyjaśniać. Możesz to porównać z podobnym przypadkiem for Module, który pozwala na konstruktywne użycie (patrz np. Tutaj stackoverflow.com/questions/7394113/… ). Problem w tym, że Blockpotrzebny jest jakiś symbol, żeby ...
Leonid Shifrin,
9

Czyste funkcje rekurencyjne ( #0) wydają się być jednym z ciemniejszych zakątków języka. Oto kilka nietrywialnych przykładów ich użycia, w których jest to naprawdę przydatne (co nie znaczy, że nie można ich bez tego zrobić). Poniżej znajduje się dość zwięzła i dość szybka funkcja znajdowania połączonych komponentów na wykresie, biorąc pod uwagę listę krawędzi określonych jako pary wierzchołków:

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

To, co się tutaj dzieje, polega na tym, że najpierw odwzorowujemy symbol fikcyjny na każdym z numerów wierzchołków, a następnie ustalamy sposób, który {f[5],f[10]}, powiedzmy, biorąc pod uwagę parę wierzchołków , f[5]dałby wynik f[10]. Rekurencyjna funkcja czysta jest używana jako kompresor ścieżki (w celu skonfigurowania zapamiętywania w taki sposób, że zamiast długich łańcuchów f[1]=f[3],f[3]=f[4],f[4]=f[2], ..., zapamiętane wartości są korygowane za każdym razem, gdy zostanie wykryty nowy „pierwiastek” składnika. Daje to znaczne przyspieszenie. Ponieważ używamy przypisania, potrzebujemy, aby było to HoldAll, co czyni ten konstrukt jeszcze bardziej niejasnym i atrakcyjniejszym). Ta funkcja jest wynikiem dyskusji w Mathgroup on-line i off-line z udziałem Freda Simonsa, Szabolcs Horvata, DrMajorBoba i naprawdę twoich. Przykład:

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

Z pewnością jest znacznie wolniejszy niż wbudowany, ale jak na rozmiar kodu, wciąż dość szybki IMO.

Inny przykład: oto rekurencyjna realizacja Select, oparta na połączonych listach i rekurencyjnych czystych funkcjach:

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

Na przykład,

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

Jednak nie jest on poprawnie rekurencyjny i spowoduje wysadzenie stosu (awarię jądra) w przypadku większych list. Oto wersja rekurencyjna ogona:

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

Na przykład,

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}} 
Leonid Shifrin
źródło
Funkcja podłączonych komponentów jest nadal moją ulubioną :-)
Szabolcs
@Szabolcs Tak, jest całkiem fajny. Ty i Fred zrobiliście większość tego, Bobby i ja dodaliśmy tylko kilka poprawek, IIRC.
Leonid Shifrin
8

To jest przepis z książki Stana Wagona ... użyj go, gdy wbudowana fabuła zachowuje się nieprawidłowo z powodu braku precyzji

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

Często używam następującej sztuczki od Kristjana Kannike, kiedy potrzebuję zachowania "podobnego do słownika" z obniżonych wartości 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]

Gdy wyniki oceny są mylące, czasami pomaga zrzucić etapy oceny do pliku tekstowego

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]]
Jarosław Bulatow
źródło
Próbka użycia byłaby świetna. Spróbuj opublikować taki, kiedy masz czas.
Dr. Belisarius
Czy znasz Kristjana? Pracowałem z nim w tej samej grupie w Helsinkach. Miły facet, mały świat.
Timo
Nie, znalazłem jego kod w sieci. Właściwie próbowałem wysłać mu e-mail, aby naprawić mały błąd w kodzie, ale e-mail na jego stronie internetowej już nie działa
Jarosław Bułatow
8

Możliwe jest uruchomienie MathKernel w trybie wsadowym przy użyciu nieudokumentowanych opcji wiersza poleceń -batchinputi-batchoutput :

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

(gdzie input.mjest wsadowym plikiem wejściowym kończącym się znakiem nowego wiersza, outputfile.txtto plik, do którego zostanie przekierowany wynik).

W Mathematica v.> = 6 MathKernel ma nieudokumentowaną opcję wiersza poleceń:

-noicon

który kontroluje, czy MathKernel będzie miał widoczną ikonę na pasku zadań (przynajmniej pod Windows).

FrontEnd (przynajmniej od wersji 5) ma nieudokumentowaną opcję wiersza poleceń

-b

co wyłącza ekran powitalny i pozwala na znacznie szybsze uruchomienie Mathematica FrontEnd

i opcja

-directlaunch

co wyłącza mechanizm, który uruchamia najnowszą zainstalowaną wersję Mathematica zamiast uruchamiania wersji związanej z plikami .nb w rejestrze systemowym.

Innym sposobem na to prawdopodobnie jest :

Zamiast uruchamiać plik binarny Mathematica.exe w katalogu instalacyjnym, uruchom plik binarny Mathematica.exe w folderze SystemFiles \ FrontEnd \ Binaries \ Windows. Pierwszy z nich to prosty program uruchamiający, który usilnie stara się przekierować żądania otwarcia notatników do uruchomionych kopii interfejsu użytkownika. Ten ostatni jest sam binarny interfejsu użytkownika.

Przydatne jest połączenie ostatniej opcji wiersza poleceń z ustawieniem globalnej opcji FrontEnd, VersionedPreferences->True która wyłącza dzielenie się preferencjami między różnymi zainstalowanymi wersjami Mathematica :

SetOptions[$FrontEnd, VersionedPreferences -> True]

(Powyższe należy ocenić w najnowszej zainstalowanej wersji Mathematica ).

W Mathematica 8 jest to kontrolowane w oknie dialogowym Preferencje, w panelu System, w ustawieniu „Utwórz i utrzymuj preferencje interfejsu specyficzne dla wersji” .

Możliwe jest pobranie niepełnej listy opcji wiersza poleceń FrontEnd za pomocą nieudokumentowanego klucza -h(kod dla Windows):

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

daje:

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

Inne opcje obejmują:

-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

Czy istnieją inne potencjalnie przydatne opcje wiersza poleceń MathKernel i FrontEnd? Udostępnij, jeśli wiesz.

Powiązane pytanie .

Alexey Popkov
źródło
"dopasowanie bitowości?" Co to znaczy?
Pan Wizard
@ Mr.Wizard Prawdopodobnie ta opcja ma sens tylko w systemach 64-bitowych w połączeniu z opcją -32i oznacza, że ​​bitowość MathKernela używanego przez FrontEnd będzie pasowała do bitowości systemu operacyjnego (64-bitowego). Wydaje się, że w innych przypadkach ta opcja niczego nie zmieni.
Alexey Popkov
7

Moimi ulubionymi sztuczkami są małe makra generujące kod, które pozwalają zastąpić kilka standardowych poleceń standardowych jednym krótkim. Alternatywnie możesz utworzyć polecenia do otwierania / tworzenia notatników.

Oto, czego używam od jakiegoś czasu w moim codziennym przepływie pracy w Mathematica. Zauważyłem, że często wykonuję następujące czynności:

  1. Spraw, aby notatnik miał prywatny kontekst, załaduj potrzebne mi pakiety, zrób to automatycznie.
  2. Po dłuższej pracy z tym notatnikiem chciałbym wyrzucić obliczenia w osobnym notatniku, z własnym kontekstem prywatnym, mając jednocześnie dostęp do definicji, których używałem w "głównym" notatniku. Ponieważ skonfigurowałem kontekst prywatny, wymaga to ręcznego dostosowania $ ContextPath

Robienie tego wszystkiego ręcznie jest uciążliwe, więc zautomatyzujmy! Najpierw trochę kodu użytkowego:

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

Teraz stwórzmy makro, które umieści następujące komórki w notatniku:

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

A oto makro:

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

Teraz, kiedy wpisuję, MyPrivatize[]tworzy kontekst prywatny i ładuje mój standardowy pakiet. Teraz stwórzmy polecenie, które otworzy nowy zeszyt z własnym kontekstem prywatnym (abyś mógł się tam włamać z dzikim porzuceniem bez ryzyka zepsucia definicji), ale ma dostęp do twoich obecnych kontekstów.

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

Fajne w tym jest to, że SelfDestructpo uruchomieniu polecenia nie pozostawia śladu w bieżącym notatniku - co jest dobre, ponieważ w przeciwnym razie po prostu stworzyłoby bałagan.

Aby uzyskać dodatkowe punkty dotyczące stylu, możesz utworzyć wyzwalacze słów kluczowych dla tych makr za pomocą InputAutoReplacements, ale zostawię to jako ćwiczenie dla czytelnika.

Leo Alekseyev
źródło
7

PutAppend with PageWidth -> Infinity

W Mathematica użycie PutAppendpolecenia jest najprostszym sposobem na utrzymanie uruchomionego pliku dziennika z wynikami obliczeń pośrednich. Ale używa domyślnego PageWith->78ustawienia podczas eksportowania wyrażeń do pliku, więc nie ma gwarancji, że każde pośrednie wyjście zajmie tylko jedną linię w dzienniku.

PutAppendsam nie ma żadnych opcji, ale śledzenie jego ocen pokazuje, że jest oparty na OpenAppendfunkcji, która ma PageWithopcję i umożliwia zmianę jej wartości domyślnej za pomocą SetOptionspolecenia:

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

Możemy więc PutAppenddołączyć tylko jedną linię naraz, ustawiając:

SetOptions[OpenAppend, PageWidth -> Infinity]

AKTUALIZACJA

W wersji 10 wprowadzono błąd (poprawiony w wersji 11.3): SetOptionsnie wpływa już na zachowanie OpenWritei OpenAppend.

Sposób obejścia problemu polega na zaimplementowaniu własnej wersji programu PutAppendz jawną PageWidth -> Infinityopcją:

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

Zwróć uwagę, że możemy również zaimplementować go za pomocą, WriteStringjak pokazano w tej odpowiedzi, ale w tym przypadku konieczne będzie wstępne przekonwertowanie wyrażenia na odpowiednie InputFormprzez ToString[expr, InputForm].

Alexey Popkov
źródło
6

Po prostu patrząc przez jednego z moich paczek do włączenia do tego, i znaleźć kilka wiadomości, że określone, że cuda działa: Debug::<some name>. Domyślnie są wyłączone, więc nie powodują dużego obciążenia. Ale mogę zaśmiecać nimi swój kod i włączać je, jeśli chcę dokładnie dowiedzieć się, jak zachowuje się fragment kodu.

rcollyer
źródło
Z Pomoc> Od wersji 2.0 (wydanej w 1991 r.) Debug został zastąpiony przez Trace.
Dr. Belisarius
1
@belisarius, przegapiłeś sedno. Nie jest Debugani Tracefunkcją ani ; jest to zestaw wiadomości, które stworzyłem, którymi mogę zaśmiecać swój kod, aby włączać / wyłączać w dowolnym momencie. Są poprzedzone słowem Debug, w taki sam sposób, jak komunikat usagejest poprzedzony nazwą funkcji. Zapewnia taką samą funkcjonalność, jak umieszczanie zestawu coutinstrukcji w kodzie C ++.
rcollyer
1
Och ... przepraszam. Byłem zdezorientowany, ponieważ nigdy nie ukończyłem przedszkola za to, że nie nauczyłem się „Stolice są dla krajów”: D
Dr belisarius
6

Jedną z rzeczy, które przeszkadzają mi w przypadku wbudowanych konstrukcji określających zakres, jest to, że oceniają one wszystkie definicje zmiennych lokalnych naraz, więc nie możesz pisać na przykład

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

Tak więc jakiś czas temu wymyśliłem makro o nazwie WithNest, które pozwala ci to zrobić. Uważam to za przydatne, ponieważ pozwala zachować lokalne powiązania zmiennych bez konieczności wykonywania czegoś takiego

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

Ostatecznie najlepszym sposobem, jaki mogłem znaleźć, aby to zrobić, było użycie specjalnego symbolu, aby ułatwić powtarzanie listy powiązań, i umieściłem definicję we własnym pakiecie, aby ukryć ten symbol. Może ktoś ma prostsze rozwiązanie tego problemu?

Jeśli chcesz to wypróbować, umieść poniższe w pliku o nazwie 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[];
DGrady
źródło
Janus opublikował wersję tego i odsyła do Twojego pytania na MathGroup: stackoverflow.com/questions/4190845/custom-notation-question/…
Mr.Wizard
Dziękuję za zwrócenie uwagi! Minęło trochę czasu, odkąd przyjrzałem się tym rzeczom i ciekawie jest zobaczyć wszystkie inne podejścia.
DGrady
5

Ten został napisany przez Alberto Di Lullo (który nie wydaje się być na Stack Overflow).

CopyToClipboard, dla Mathematica 7 (w Mathematica 8 jest wbudowany)

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

Oryginalny post: http://forums.wolfram.com/mathgroup/archive/2010/Jun/msg00148.html

Zauważyłem, że ta procedura jest przydatna do kopiowania dużych liczb rzeczywistych do schowka w zwykłej postaci dziesiętnej. Na przykładCopyToClipboard["123456789.12345"]

Cell[OutputFormData@expr] starannie usuwa cytaty.

Chris Degnen
źródło
5

Ten kod tworzy paletę, która przesyła zaznaczenie do Stack Exchange jako obraz. W systemie Windows dostępny jest dodatkowy przycisk, który zapewnia wierniejsze renderowanie zaznaczenia.

Skopiuj kod do komórki notesu i oceń. Następnie wyjmij paletę z wyjścia i zainstaluj ją za pomocąPalettes -> Install Palette...

Jeśli masz z tym jakiś problem, napisz komentarz tutaj. Pobierz wersję notebooka tutaj .


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[];
Szabolcs
źródło
4

Jestem pewien, że wiele osób spotkało się z sytuacją, w której uruchamiają jakieś rzeczy, zdając sobie sprawę, że nie tylko utknęli w programie, ale także nie zapisali przez ostatnie 10 minut!

EDYTOWAĆ

Po pewnym czasie cierpienia z tego powodu, pewnego dnia odkryłem, że można utworzyć automatyczne zapisywanie z poziomu kodu Mathematica . Myślę, że korzystanie z takiego automatycznego zapisywania bardzo mi pomogło w przeszłości i zawsze uważałem, że sama możliwość jest czymś, o czym niewiele osób zdaje sobie sprawę, że mogą zrobić.

Oryginalny kod, którego użyłem, znajduje się na dole. Dzięki komentarzom dowiedziałem się, że jest to problematyczne i dużo lepiej jest to zrobić w alternatywny sposób, używając ScheduledTask(co zadziała tylko w Mathematica 8).

Kod do tego można znaleźć w tej odpowiedzi od Sjoerd C. de Vries (Ponieważ nie jestem pewien, czy mogę go tutaj skopiować, zostawiam go tylko jako łącze).


Poniższe rozwiązanie używa Dynamic. Zapisuje notatnik co 60 sekund, ale najwyraźniej tylko wtedy, gdy jego komórka jest widoczna . Zostawiam to tutaj tylko z powodów ukończenia. (oraz dla użytkowników Mathematica 6 i 7)

/EDYTOWAĆ

Aby go rozwiązać, używam tego kodu na początku notatnika:

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

Pozwoli to zaoszczędzić Twoją pracę co 60 sekund.
Wolę to robić, NotebookAutoSave[]ponieważ zapisuje przed przetworzeniem danych wejściowych i ponieważ niektóre pliki zawierają więcej tekstu niż danych wejściowych.

Pierwotnie znalazłem to tutaj: http://en.wikipedia.org/wiki/Talk:Mathematica#Criticisms

Zwróć uwagę, że po uruchomieniu tej linii zapisywanie nastąpi nawet po zamknięciu i ponownym otwarciu pliku (o ile włączone jest dynamiczne aktualizowanie).

Ponadto, ponieważ w Mathematica nie ma możliwości cofnięcia , uważaj, aby nie usunąć całej zawartości, ponieważ zapisanie spowoduje, że będzie ona nieodwracalna (na wszelki wypadek usuwam ten kod z każdego gotowego notatnika)

tsvikas
źródło
możesz również zapisać go pod inną nazwą (np. dodając aktualną godzinę i datę na końcu nazwy pliku) i być może w określonym katalogu (powiedzmy „Kopie zapasowe”). byłoby to prymitywną formą wersjonowania.
acl
Możesz zrobić coś takiego NotebookSave[SelectedNotebook[], "work-" <> IntegerString[i] <> ".nb"]; i++, ale myślę, że każde odwołanie do aktualnej nazwy notatnika stanie się rekurencyjne.
tsvikas
2
Myślałem, że Dynamicobiekty odświeżają się tylko wtedy, gdy są widoczne, więc nie byłbym pewien, czy ta metoda zadziała, jeśli np. Przewiniesz Dynamicobiekt poza widoczny obszar. Z drugiej strony, nie próbowałem. W każdym razie zaproponowałem to tylko jako sugestię.
ACL
1
Możesz to sprawdzić za pomocą Dynamic[Refresh[i++, UpdateInterval -> 1, TrackedSymbols -> {}]]. Przewiń rosnącą liczbę z pola widzenia, poczekaj minutę, przewiń do tyłu i zobacz, że liczba nie jest zwiększana o 60. Informacje UpdateInterval: jest to zwykle używane, jeśli to możliwe, ale jeśli kod zawiera zmienne, które się zmieniają, ta zmiana wyzwala nowe odświeżanie przed interwał się kończy. Wypróbuj powyższą linię bezTrackedSymbols
Sjoerd C. de Vries
1
@ j0ker5 Wypróbuj mój powyższy kod, a zobaczysz, że UpdateInterval nie zawsze wymusza odstępy między aktualizacjami w określonym interwale. Ten kod pokazuje również, że Dynamic działa tylko wtedy, gdy komórka, w której się znajduje, jest widoczna w interfejsie użytkownika . Naprawdę zatrzymuje się, gdy zniknie z pola widzenia. Ludzie naprawdę nie powinni ufać temu kodowi przy zapisywaniu ich plików, ponieważ tak nie jest. To niebezpieczne
Sjoerd C. de Vries
3

Uważam, że przy tworzeniu pakietów bardzo przydatne jest dodanie tego skrótu klawiaturowego do mojego SystemFiles/FrontEnd/TextResources/Windows/KeyEventTranslations.trpliku.

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

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

Następnie za każdym razem Packagename.mrobię PackagenameTest.nbnotatnik do testów i pierwsze 2 komórki testowego notatnika są ustawiane jako komórki inicjalizacyjne. W pierwszej celi umieściłem

Needs["PackageManipulations`"]

aby załadować bardzo przydatną bibliotekę PackageManipulations napisaną przez Leonida. Druga komórka zawiera

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

które wszystkie dokonują właściwego przeładowania pakietu. Zwróć uwagę, że pierwsze dwie linie są dostępne tylko dla Removewszystkich symboli, ponieważ lubię, aby konteksty były jak najczystsze.

Następnie przepływ pracy przy pisaniu i testowaniu pakietu wygląda mniej więcej tak.

  1. Zapisz zmiany w Packagename.m.
  2. Idź PackagenameTest.nbi zrób CTRL + ALT + i.

Powoduje to ponowne załadowanie pakietu przez komórki inicjalizacyjne, co sprawia, że ​​testowanie jest naprawdę proste.

Nixeagle
źródło
1

Poniższa funkcja format[expr_]może służyć do tworzenia wcięć / formatowania niesformatowanych mathematicawyrażeń, które obejmują całą stronę

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

Prashant Bhate
źródło
Do czego to używasz w praktyce? Wynik jest trochę zbyt "zabawny", aby można go było odczytać zarówno po zastosowaniu do kodu, jak i do danych (list format@RandomInteger[10,{3,3}]): pastebin.com/nUT54Emq Skoro masz już podstawy i jesteś tym zainteresowany, czy możesz ulepszyć kod tak, aby stworzyć użyteczne, czytelne formatowanie? Następnie następnym krokiem byłoby utworzenie przycisku wklejania, który utworzy komórkę wejściową z ładnie wciętym kodem Mathematica (najlepiej z zachowaniem komentarzy !!). Zobacz także moje powiązane pytanie .
Szabolcs