Ich habe ein Buch mit über 800 Seiten und es lässt sich mit xelatex und forest 1.05 unter texlive 2015 problemlos kompilieren. Ich migriere zu texlive 2016, da mein Übersetzer mit forest 2.0 funktioniert. Jetzt erhalte ich:
! TeX capacity exceeded, sorry [pool size=6143546].
\safeiterate@4 ...@countc y\endcsname )\endcsname
\forest@inpath \forest@tem...
l.770 }
Wenn ich den Forest-Code entferne, bekomme ich später den Fehler. Wenn ich kleinere Teile texe, ist alles in Ordnung. Ich vermute also, dass es wirklich ein Speicherproblem ist.
Frage: Kann ich außer der Änderung einiger Tex-Konfigurationsdateien noch etwas anderes tun? Der Code soll für mehrere Benutzer ausgeführt werden und die Änderung von Speichervariablen wäre ungünstig.
Entschuldigung, hier gibt es kein Minimalbeispiel, aber ich könnte den Code auf GitHub oder woanders verfügbar machen.
Bearbeiten: OK. Es muss Forest 2.0 sein, denn wenn ich Forest 1.05 lade, während Texlive 2016 läuft, ist alles in Ordnung.
Antwort1
Dies war tatsächlich ein Gesamtstrukturproblem, das aber überraschenderweise schon seit der allerersten Version des Pakets vorhanden war. Stefan war einfach der Erste, der ein so langes, baumartiges Dokument erstellt hat ... und der Wechsel von v1 zu v2 hat das Problem nur noch schlimmer gemacht.
Bevor ich erkläre, was schief gelaufen ist: Ich habe gerade die korrigierte Version (v2.1.4) auf CTAN gepostet.
Das Problem war genau das, was Ulrike Fischer in einem Kommentar oben erwähnt hat. Forests Packalgorithmus muss (vorübergehend) einige Informationen über Koordinaten (und Koordinatenpaare) speichern. Außerdem muss er bei einer gegebenen Koordinate (oder einem Paar) die Informationen dazu schnell abrufen können. Die offensichtliche Lösung besteht darin, die Informationen in einem Wörterbuch (assoziatives Array) zu speichern, wobei die Koordinaten der Suchschlüssel sind. Daher schien die Verwendung der Steuersequenzen von TeX eine perfekte Idee zu sein, und ich habe es naiv getan (im Wesentlichen durch Kopieren und Einfügen aus meiner Proof-of-Concept-Python-Implementierung):
\csdef{forest@(\the\pgf@x,\the\pgf@y)}{...}
und selbst
\csdef{forest@(\the\pgf@xa,\the\pgf@ya)--(\the\pgf@xb,\the\pgf@yb)}{...}
ohne zu bedenken, dass die Definitionen zwar lokal sind, die Einträge aber für immer in der Hash-Tabelle von TeX verbleiben. Dieser Ansatz verbrauchte leicht einige Kilobyte an String-Pool-Speicherplatzpro Baum!
v2.1.4 implementiert die fehlerhaften Wörterbücher neu, indem alle Informationen in einem einzigen Toks-Register gespeichert werden, dessen Inhalt wie folgt aussieht (wird nur für das erste der oben genannten Probleme angezeigt):
...(x1,y1){...}(x2,y2){...}...
In einer solchen Struktur ist es einfach, nach einer bestimmten Koordinate zu suchen (wenn auch langsamer als im \csname
Ansatz):
\def\forest@breakpath@getfromtoks#1#2#3#4{%
% #1=cache toks register, #2=receiving cs, (#3,#4)=point;
% we rely on the fact that the point we're looking up should always be present
\def\forest@breakpath@getfromtoks@##1(#3,#4)##2##3\forest@END{##2}%
\edef#2{\expandafter\forest@breakpath@getfromtoks@\the#1\forest@END}%
(Viele Pakete verwenden ein solches System, siehe zB\ PGFs \pgfutil@in@
.)
Das neue System ist etwa 10 % langsamer, aber: In Stefans über 800 Seiten starkem Buch, wo Version v2.1.3 das Limit von 6 Millionen Zeichenketten überschritt, verbraucht v2.1.4 (und alle anderen geladenen Pakete) nur magere 2 Millionen. In Bezug auf den Speicherverbrauch des Packalgorithmus spielt die Dokumentlänge eigentlich keine Rolle mehr.
Danke, Stefan, dass du das gefunden hast und die ganze letzte Woche mit mir ausgehalten hast! (Tipp: Wenn ich mir den Packalgorithmus nach diesen paar Jahren noch einmal anschaue, glaube ich, dass er auch viel schneller gemacht werden könnte!)